Comment lire une donnée binaire sur un terminal série dans un programme C?
J'ai lu, suivi des liens et d'autres sources, mais je n'ai pas trouver réponse à ma question.
Données binaires sur le terminal série
De données est corrompu lors de leur transmission via le port série
- Je communiquer avec mon appareil embarqué par l'intermédiaire d'un port série. Par défaut, Linux embarqué utilise ce port comme un terminal. Mais je veux aussi transmettre des données binaires (paquets de service) par le port. Mon fichier /etc/inittab a un "getty" composez le:
console::respawn:/sbin/getty 115200 ttyS0
J'ai aussi fichier /etc/passwd avec de la ficelle où l'utilisateur "admin" lancer mon "cli" application après l'ouverture de session:
admin:8Mt/Jtxcyg8AY:1000:0:admin:/tmp:/tmp/cli
Par défaut de mon ttyS0 paramètres avant d'exécuter le programme est:
~ # stty -a
speed 115200 baud;stty: standard input
line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = ^J;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon ixoff
-iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon -iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
-echoctl echoke
~ #
Donc, dans mon programme en ligne de commande je ne les suivants:
main ()
{
...
system("stty erase ^H);
system("stty -F /dev/ttyS0 -icrnl -ixon -ixoff -opost -isig -icanon -echo"); //enter in non-canonical (raw) mode
//What function do I need to use here to retrieve binary data (also symbols that > 0x7F) from /dev/ttyS0?
system("stty -F /dev/ttyS0 icrnl ixon ixoff opost isig icanon echo"); //go back to canonical mode
...
exit(0);
}
J'ai tenté de lire() fonction (avec unsigned char buffer) pour obtenir des données binaires, mais a échoué à recevoir des données correctes. J'ai aussi préalablement ouvrir /dev/ttyS0 de nouveau pour obtenir file_descriptor & lire() func.
Mon programme envoie 3 octets: 0xAA, 0x02, 0xFE.
Mais dans syslog, je vois toujours que l'appareil reçoit des symboles incorrects: 0x98, 0xE6, 0x18.
Quelle est la question? Comment obtenir correcte des données binaires?
Tout un code que je suis en train de tester en ce moment.
#include "cli.h"
#include "glb_vars.h"
/******************************************
*** Definitions
******************************************/
#define APPLICATION_NAME "cli"
#define SERIALPORT_IS_CONSOLE
/******************************************
*** Constants
******************************************/
const char dev_name[] = DEV_NAME;
const char lineminstr[] = "\t--------------------------------------------------------\n";
/******************************************
*** Internal Function Declarations
******************************************/
CLI_RETVAL cliInit(void);
CLI_RETVAL cliClose(void);
void cliWorkLoop(Term_callback_t **term);
/******************************************
*** External Function Declarations
******************************************/
extern void Vectors_init(Term_callback_t **vec);
extern char** Menu_completion(const char * text, int start, int end);
/****************************************************************************/
int file_descr, max_fd;
struct termios tty, orig_tty;
fd_set work_set;
/****************************************************************************/
/*!
* \brief Init cli
*
* \return success or failure
* \retval CLI_SUCCESS, CLI_FAILURE
*
* \ingroup CLI
*/
/****************************************************************************/
CLI_RETVAL cliInit(void)
{
long spd;
signal(SIGINT, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGTERM, SIG_IGN);
signal(SIGABRT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGILL, SIG_IGN);
// system("stty -F /dev/ttyS0 -icrnl -ixon -ixoff -opost -isig -icanon -echo"); //enter in non-canonical mode
// system("stty -a");
// sleep(1);
#ifdef SERIALPORT_IS_CONSOLE
file_descr = STDIN_FILENO;
SYS_LOG_DEBUG("SERIALPORT IS CONSOLE");
#else
SYS_LOG_DEBUG("SERIALPORT IS NOT CONSOLE");
file_descr = open("/dev/ttyS0", O_RDWR | O_ASYNC | O_NDELAY);
if (file_descr == -1) {
//Could not open the port
perror("unable to open /dev/ttyS0");
exit(1);
}
#endif
if(tcgetattr(file_descr, &tty) < 0)
{
perror("unable to get tty attributes");
exit(1);
}
//backup tty, make it raw and apply changes
orig_tty = tty;
spd = B115200;
cfsetospeed(&tty, (speed_t)spd);
cfsetispeed(&tty, (speed_t)spd);
cfmakeraw(&tty);
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 10;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS; /* no HW flow control? */
tty.c_cflag |= CLOCAL | CREAD;
tcsetattr(file_descr, TCSANOW, &tty);
// //update local mode flags
// tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
//// //renew control mode flags
//// tty.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | PARENB | PARODD);
//// tty.c_cflag |= (BAUD | DATABITS | STOPBITS | PARITYON | PARITY);
// //select 'raw' output mode
// tty.c_oflag &= ~OPOST;
// //disable mapping for input mode
// tty.c_iflag &= ~(INLCR | ICRNL);
//
//
// if(tcsetattr(file_descr, TCSAFLUSH, &tty) < 0)
// {
// perror("unable to set tty attributes");
// exit(1);
// }
//
//Setup fd_set
FD_ZERO(&work_set);
FD_SET(file_descr, &work_set);
max_fd = file_descr + 1;
/* Readline lib init */
//Define application name for readline library
rl_readline_name = APPLICATION_NAME;
//Update Pointer to alternative function to create matches.
rl_attempted_completion_function = Menu_completion;
//Start readline with reading /etc/inputrc file
using_history();
stifle_history(CLI_MAX_HISTORY_SIZE);
//Some other initialization code
//...
//...
return CLI_SUCCESS;
}
/****************************************************************************/
/*!
* \brief Close cli
*
* \return success or failure
* \retval CLI_SUCCESS, CLI_FAILURE
*
* \ingroup CLI
*/
/****************************************************************************/
CLI_RETVAL cliClose(void)
{
// system("stty -F /dev/ttyS0 icrnl ixon ixoff opost isig icanon echo"); //enter in canonical mode
tcsetattr(file_descr, TCSANOW, &orig_tty);
// if(tcsetattr(file_descr, TCSAFLUSH, &orig_tty) < 0)
// {
// perror("unable to set orig_tty attributes");
// exit(1);
// }
close(file_descr);
return CLI_SUCCESS;
}
/****************************************************************************/
/*!
* \brief Main cli processing loop
*
* \no return
*
* \ingroup CLI
*/
/****************************************************************************/
void cliWorkLoop(Term_callback_t **term)
{
Term_callback_t *cur_term;
int8 *commandString;
uint8 ret = CLI_REFRESH, no_prompt;
char prompt_str[20];
while (1) {
cur_term = *term;
global_cmd_compl_pointer = cur_term->cmd_list;
commandString = NULL;
sprintf(prompt_str, "%s:~> ", dev_name);
if(ret == CLI_REFRESH) {
CLEAR_SCR();
if(cur_term->out != NULL) {
cur_term->out(term, commandString, &ret);
no_prompt = ret;
}
CURSOR_DOWN();
}
int n;
struct timeval timeout;
uint8 tmpBuf[32];
while (1)
{
//Setup Timeout
timeout.tv_sec = 60;
timeout.tv_usec = 0;
//Wait for new connections
n = select(max_fd, &work_set, NULL, NULL, &timeout);
if (n < 0)
{
perror("select #2 failed");
break;
}
if (n > 0)
{
/* У нас есть ввод */
if (FD_ISSET(file_descr, &work_set))
{
if (read(file_descr, tmpBuf, 10) < 0) {
perror("cannot read");
exit(1);
}
else
{
SYS_LOG_DEBUG("READ first 4 chars: 0x%X,0x%X,0x%X,0x%X", tmpBuf[0], tmpBuf[1], tmpBuf[2], tmpBuf[3]);
}
}
break;
}
}
//
//
// n = read(file_descr, tmpBuf, 5);
// if (n > 0) {
// unsigned char *p = tmpBuf;
//
// while (n-- > 0)
// printf(" 0x%x", *p++);
// printf("\r\n");
// } else {
// printf("failed to read: %d\r\n", n);
// }
//
//
exit(0);
}
CLEAR_SCR();
return;
}
/****************************************************************************/
/*!
* \brief Main cli function
*
* \param[in] argc - argument number.
* \param[in,out] argv - argument values entered by user.
*
* \return success or failure
* \retval EXIT_SUCCESS, EXIT_FAILURE
*
*
* \ingroup CLI
*/
/****************************************************************************/
int main(int argc, char *argv[])
{
Term_callback_t *term;
char logname[16];
FILE *fp;
/* Set mask for file operation */
umask(0);
system("stty erase ^H");
openlog("cli", LOG_CONS, LOG_USER);
/* Write cli start log */
syslog(LOG_NOTICE, "Console startup. Software version: %s", VERSION);
/* Find login name */
strcpy(logname, "noname");
if ((fp = popen( "whoami", "r" )) == NULL)
{
SYS_LOG_ERR("Can't open process for \"whoami\" command.");
} else
{
fgets(logname, 16, fp);
pclose(fp);
}
SYS_LOG_INFO("Console is entered by \"%s\".", logname); //getenv("USER")
/* Console initialization */
if (cliInit() != CLI_SUCCESS) {
SYS_LOG_CRIT("CLI init failed");
return EXIT_FAILURE;
}
Vectors_init(&term);
/* Console work loop */
cliWorkLoop(&term);
cliClose();
/* Exiting from cli */
SYS_LOG_INFO("\"%s\" exited from console.", logname);
return EXIT_SUCCESS;
}
source d'informationauteur Bakir
Vous devez vous connecter pour publier un commentaire.
Ce serait insuffisante code (et mauvaises pratiques de codage par POSIX conventions) pour mettre le port série dans les matières premières ou la non-canonique de la mode.
La méthode la plus simple en C et Linux est d'utiliser la fonction
cfmakeraw()
qui est disponible dans les deux GNU libc et uClibc bibliothèques. Utiliser le homme page pour obtenir les détails sur la termios membres de structure qui sont modifiés parcfmakeraw()
.Méfiez-vous que
cfmakeraw()
permet de configurer le port série en mode raw pour une longueur de données de 8 bits, et pas de la parité, pour un total de caractères cadre de 10 bits (en supposant un bit de stop).La méthode préférée est de préserver une copie de la termios stucture (pour la restauration sur la sortie du programme) et de modifier uniquement le nécessaire drapeau bits (plutôt que d'écrire la structure complète des membres).
RÉVISION
Code qui fonctionne sur mon BRAS SoC est:
Le programme compilé est chargé & exécuté sur la carte cible.
À partir de l'hôte de la série comm lien, le fichier
seq.bin
avec le contenu suivant est envoyé:Puis "ABC" est tapé sur l'ordinateur hôte (qui est en cours d'exécution de la
minicom
programme d'émulation de terminal), suivi d'un retour chariot.Le programme se termine sur la cible, et le syslog est ensuite examiné:
Les données binaires a été reçu intact.
De noter que, puisque c'est le mode raw et le tapé les caractères ont été saisis relativement lentement, le
read()
renvoie "partielle" des données et le programme de l'utilisateur serait responsable de la mise en mémoire tampon/assembler les données complète d'un "messages". Si les messages sont de longueur fixe, puisc_cc[VMIN]
membre pourrait être réglé à la longueur du message. Mais méfiez-vous du message de cadrage des problèmes et des complications lors de la synchronisation des images est perdu!