How to retarget printf() on an STM32F10x? - c

I use this code for retarget printf(), but it does not work
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the LCD */
lcd_Data_Write((u8)ch);
return ch;
}
I use STM32F103RBT6
compiler : GCC with emBitz editor

Try hijacking the _write function like so:
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
int _write(int file, char *ptr, int len)
{
switch (file)
{
case STDOUT_FILENO: /*stdout*/
// Send the string somewhere
break;
case STDERR_FILENO: /* stderr */
// Send the string somewhere
break;
default:
return -1;
}
return len;
}

As an alternative, you could write your own printf() function using, Variable Argument Functions (va_list).
With va_list a custom print function looks like the following:
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
void vprint(const char *fmt, va_list argp)
{
char string[200];
if(0 < vsprintf(string,fmt,argp)) // build string
{
HAL_UART_Transmit(&huart1, (uint8_t*)string, strlen(string), 0xffffff); // send message via UART
}
}
void my_printf(const char *fmt, ...) // custom printf() function
{
va_list argp;
va_start(argp, fmt);
vprint(target, fmt, argp);
va_end(argp);
}
Usage example:
uint16_t year = 2016;
uint8_t month = 10;
uint8_t day = 02;
char* date = "date";
// "Today's date: 2015-12-18"
my_printf("Today's %s: %d-%d-%d\r\n", date, year, month, day);
Note that while this solution gives you convenient function to use, it is slower than sending raw data or using even sprintf(). I have used this solution both on AVR and on STM32 microcontrollers.
You could further modify the vprint like this, where periphery_t is a simple enum type:
void vprint(periphery_t target, const char *fmt, va_list argp)
{
char string[200];
if(0 < vsprintf(string,fmt,argp))
{
switch(target)
{
case PC: PC_send_str(string);
break;
case GSM: GSM_send_str(string);
break;
case LCD: LCD_print_str(string);
break;
default: LCD_print_str(string);
break;
}
}
}

Tank you Bence Kaulics
I use tinyprintf library and it worked quite well : github link

just make sure to add the following in the init code:
// Turn off buffers, so I/O occurs immediately
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);

Related

compilation warnings in the program that uses lseek for reading

My program opens a read-write file with the append flag to read from any position specified with lseek. But I'm getting some compilation warnings and I'd like you to help me remove them. What is the problem?
#include "lab.h"
#include <fcntl.h>
#define BUFFERSIZE 1024
int main(int argc, const char *argv[])
{
int fd;
char buffer[BUFFERSIZE];
char dx[] = "C is awesome";
if ((fd = open("test", O_APPEND)) < 0)
{
err_sys("open error");
}
if (write(fd, dx, sizeof(dx)) != sizeof(dx)) {
err_sys("write error");
}
if(lseek(fd, 0, SEEK_END) == -1)
{
err_sys("lseek error1");
}
if (read(fd, buffer, BUFFERSIZE) > 0)
{
puts(buffer);
}
if(write(fd, dx, sizeof(dx)) != sizeof(dx))
{
err_sys("write error1");
}
if (lseek(fd, 0, SEEK_CUR) == -1) /* EOF */
{
err_sys("lseek error2");
}
if (read(fd, buffer, BUFFERSIZE) > 0)
{
puts(buffer);
}
if (write(fd, dx, sizeof(dx)) != sizeof(dx))
{
err_sys("write error2");
}
if(lseek(fd, 0, SEEK_SET) == -1) /* the beginning of file */
{
err_sys("lseek error3");
}
if (read(fd, buffer, BUFFERSIZE) > 0)
{
puts(buffer);
}
if ((write(fd, dx, sizeof(dx))) != sizeof(dx))
{
err_sys("write error3");
}
close(fd);
return 0;
}
header:
#ifndef __LAB_H__
#define __LAB_H__
#include <sys/types.h> /* required for some of our prototypes */
#include <stdio.h> /* for convenience */
#include <stdlib.h> /* for convenience */
#include <string.h> /* for convenience */
#include <unistd.h> /* for convenience */
#define MAXLINE 4096 /* max line length */
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
/* default file access permissions for new files */
#define DIR_MODE (FILE_MODE | S_IXUSR | S_IXGRP | S_IXOTH)
/* default permissions for new directories */
/* prototypes for our own functions */
char *path_alloc(int *); /* {Prog pathalloc} */
int open_max(void); /* {Prog openmax} */
void clr_fl(int, int); /* {Prog setfl} */
void set_fl(int, int); /* {Prog setfl} */
void err_dump(const char *, ...); /* {App misc_source} */
void err_msg(const char *, ...);
void err_quit(const char *, ...);
void err_ret(const char *, ...);
void err_sys(const char *, ...);
#endif /* __LAB_H__ */
warnings receive:
gcc -Wall -Wextra -O -g -D_FORTIFY_SOURCE=2 -I../exemple/ append.c ../exemple/liblab.a -o append
append.c: In function ‘main’:
append.c:6:14: warning: unused parameter ‘argc’ [-Wunused-parameter]
6 | int main(int argc, const char *argv[])
| ~~~~^~~~
append.c:6:32: warning: unused parameter ‘argv’ [-Wunused-parameter]
6 | int main(int argc, const char *argv[])
| ~~~~~~~~~~~~^~~~~~
-Wall -Wextra is a very high warning level to use, and some of the sub-options it includes produce warnings that are not helpful in all situations. It is okay to compile without -Wextra or to turn off specific options as by using -Wno-unused-parameter to turn off the unused-parameter warning.
Often, any parameter declared in a function prototype is needed to perform the function’s purpose. So, if the parameter does not appear anywhere in the function definition, it could be a sign that some mistake has been made. This is not always true. For example, a program could have a class of functions that all have the same parameters because they are used in some common way, but some of the functions in the class do not need all the parameters. So it is not always a mistake not to use all parameters.
In addition to turning off the specific warning, you can tell the compiler the parameters are deliberately unused by inserting these lines in your main routine:
(void) argc;
(void) argv;
These are expressions that use the parameters argc and argv, but the void cast tells the compiler to discard the values of the expressions. It tells the compiler you are deliberately ignoring these values, and then the compiler will not warn that the parameters are not used.
Because main is a special function, it may be declared as int main(void) or int main(int argc, char *argv[]) (or equivalent). So another solution is to use the alternate declaration for main, int main(void). When this warning occurs with ordinary functions, an option might be to remove the unused parameter from the declaration of the function, as long as the function does not need to have that parameter for some other reason.
You aren't using the argc and argv variables and when you compile the solution, the compiler displays a warning for each of these.
Change the signature of int main(int argc, const char *argv[]) to plain int main() and it should compile without warnings.

How to cast char* to char *const* in C

I am trying to use the execv() function.
I am trying to pass in my argument command to the left side.
execv(file,arguments);
I am using a char * to parse the incoming user input for my shell.
The second argument of execv takes a char * const*.
Is there a way I can cast a char * const to a char * const*?
I try this below,
char * arg;
char *const a[] = (char *const)arg;
error: invalid initializer
char *const a[] = (char *const)arg;
^
But it does not work and gives me errors.
Help would be apprecieated.
The error in char *const a[] = (char *const)arg; is not due to an improper conversion. It is because char *const a[] declares an array, and the initializers for an array must be in braces1, { … }, but you have specified just one initializer without braces.
Furthermore, the argv parameter to execv should be an array of pointers in which the first points to a string containing the file name of the program being executed (this is by convention, not required) and the last is a null pointer. Thus, your definition of a ought to be something like:
char * const a[] = { FileNameOfProgram, arg, NULL };
Footnote
1 Except when a string literal is used to initialize an array, but that is not the case here.
You're trying to initialize an array. Instead of doing this,
char * arg;
char *const a[] = (char *const)arg;
do this:
char * arg;
char *const a[] = {(char *const)arg};
It's quite normal to do an execv after eliminating the command name and some of the first parameters. For example, if you have some code like (you had better to post a complete and verifiable example) let's assume you are doing something like this (if you want an example, look for the xargs(1) manpage, you have a command, and after processing the options and their parameters, you want to eliminate all of them, and execute the rest as if it was a command line, e.g. I have a command to execute repeatedly a command, delaying some specified time, like:
cont -t 0.1 -- df -k .
I use <getopts.h> to process the options of my cont program, then execute repeatedly the command df -k. Options allow to show a version for the program, to specify timeout, be verbose, or the number of times to execute the command. I wrote it just now, to show you how to do it (the example includes fork(2) use, execvp(2) and redirection to capture the output of the command to be able to go back to the origin, once known the number of lines we have received, the program uses an ANSI escape to move the cursor back to the beginning.)
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define F(_fmt) "%s:%d: " _fmt, __FILE__, __LINE__
#define FLAG_VERBOSE (1<<0)
#define FLAG_VERSION (1<<1)
#define FLAG_DELAY (1<<2)
#define FLAG_NTIMES (1<<3)
int flags = 0;
useconds_t delay = 1000000;
size_t ntimes;
void doVersion(void)
{
fprintf(stderr,
"cont: v1.0\n"
"(C) Luis Colorado. All rights reserved.\n"
"License: BSD\n");
exit(EXIT_SUCCESS);
}
ssize_t loop(int argc_unused, char **argv)
{
int fd[2];
int res = pipe(fd);
res = fork();
if (res < 0) {
fprintf(stderr,
F("fork: ERROR %d: %s\n"),
errno,
strerror(errno));
return -1;
} else if (res == 0) { /* child */
close(fd[0]); /* not going to use it */
dup2(fd[1], 1); /* redirect output to pipe */
close(fd[1]);
execvp(argv[0], argv);
fprintf(stderr,
F("execv: ERROR %d: %s\n"),
errno, strerror(errno));
return -1;
} else { /* parent */
pid_t cld_pid = res;
close(fd[1]); /* no writing to the pipe */
FILE *f = fdopen(fd[0], "rt"); /* just reading */
int c;
size_t lines = 0;
while((c = fgetc(f)) != EOF) {
if (c == '\n') lines++;
putc(c, stdout);
}
wait(NULL);
return lines;
}
} /* loop */
int main(int argc, char **argv)
{
int opt;
float t;
while ((opt = getopt(argc, argv, "t:Vvn:")) >= 0) {
switch(opt) {
case 't': flags |= FLAG_DELAY;
t = atof(optarg);
break;
case 'V': flags |= FLAG_VERSION;
break;
case 'v': flags |= FLAG_VERBOSE;
break;
case 'n': flags |= FLAG_NTIMES;
ntimes = atoi(optarg);
break;
/* ... */
}
}
if (flags & FLAG_VERSION)
doVersion();
/* the next pair of sentences is like `shift optind' in the shell. */
/* trick, don't move the parameters, just move the pointer */
argc -= optind; /* adjust the number of parameters. */
argv += optind; /* advance the pointer to the proper place */
/* NOW, argc && argv are identical to the original ones, but lacking the
* first `optind' argument strings. As the original string array ended
* in a NULL, there's no need to construct it from allocating memory.
* Anyway, we're not going to use after it's consumed in main(). */
if (flags & FLAG_VERBOSE) {
char *sep = "About to execute: ";
int i;
for (i = 0; i < argc; i++) {
fprintf(stderr, "%s%s", sep, argv[i]);
sep = " ";
}
fprintf(stderr, "\n");
}
if (flags & FLAG_DELAY) {
delay = t * 1.0E6;
}
size_t total_lines = 0;
ssize_t n = 0;
while(!(flags & FLAG_NTIMES) || ntimes--) {
/* move up as many lines as input from subcommand */
if (n) printf("\r\033[%ldA#\b", n);
n = loop(argc, argv);
if (n < 0) {
/* we have already written the error */
exit(EXIT_FAILURE);
}
usleep(delay);
total_lines += n;
}
if (flags & FLAG_VERBOSE) {
fprintf(stderr,
F("Total lines: %lu\n"),
total_lines);
}
exit(EXIT_SUCCESS);
}
you can download a complete version of this program from Github

Can't figure out seg fault

Why do I keep getting a set fault when I try and pass -H in the command line as a flag? -h (help) is working perfectly but -H(header) messes up every single time.
I have a main function as well which calls parse_command_line by passing the argc & argc.
the bool is defined as bool header = false;
the file is char** file = NULL;
and the reason I have the file+=1; in the code is so that it compiles because I am using a makefile that changes all warnings into errors.
#include "parse.h" /* prototypes for exported functions */
#include "../main/unused.h"
#include <stdlib.h>
#include <getopt.h>
#include <stdio.h>
#include <stdint.h>
int
parse_command_line (int argc, char **argv, bool *header, char **file)
{
int oc = 0;
file += 1;
bool help = false;
struct option long_options[] =
{
{"header", no_argument, NULL, 'H'},
{"help", no_argument, NULL, 'h'},
{0, 0, 0, 0}
};
while ((oc = getopt_long(argc, argv, "+Hh", long_options, NULL)) != -1)
{
printf("The value of oc = %d\n", oc);
switch(oc)
{
case 'h':
help = true;
break;
case 'H':
printf("inside case H");
*header = true;
break;
case '?':
fprintf(stderr, "Unknown flag = -%c, type -h or --help for help!\n", optopt);
exit(EXIT_FAILURE);
break;
default:
break;
}
}
printf("Out of loop"); if (optind+1 != argc)
{
fprintf(stderr, "Uh oh, invalid input! Try again with -h or --help for help!\n");
exit(EXIT_FAILURE);
}
if (help)
{
printf("\nHaving some trouble? Let me show you the ropes!\n\n");
printf("Format: ydi <option(s)> mini-elf-file\n\n");
printf("Here's your options:\n");
printf("-h --help Display usage\n");
printf("-H --header Show the Mini-Elf header\n");
exit(1);
}
if (header)
{
printf("Inside HEader");
FILE *file;
uint16_t nums[6];
file = fopen(argv[optind], "r");
#define STRUCT_ITEMS 7
fread(nums, 16, 6, file);
int cur_print;
for (cur_print = 0; cur_print < STRUCT_ITEMS; cur_print++)
{
printf("%d ", nums[cur_print]);
}
}
return 0;
}
My parse.h file is as follows:
#ifndef __PARSE_COMMAND_LINE__
#define __PARSE_COMMAND_LINE__
#include <stdbool.h>
int parse_command_line (int argc, char **argv, bool *header, char **file);
#endif
There are other files such as elf.h and elf.c which I have not implemented and are not called at all at this point, which leads me to believe they are not going to be the problem and don't need to post the small 2 line files. My main function is as follows:
#include <stdio.h> /* standard I/O */
#include <stdlib.h>
#include "unused.h" /* UNUSED macro */
#include "../cmdline/parse.h" /* command line parser */
#include "../y86/elf.h" /* Mini-ELF format */
int
main (int argc UNUSED, char **argv UNUSED)
{
printf ("Congratulations, you have compiled your source code!\n");
bool header = false;
char **file = NULL;
parse_command_line (argc, argv, &header, file);
return 0;
}
And the file unused.h (because the compiler will make unused variables an error instead of warning) is as follows:
#ifndef __UNUSED__
#define __UNUSED__
#define UNUSED __attribute__ ((unused))
#endif
The code doesn't check the return value of fopen, which will be NULL in case of an error. Dereferencing NULL in the fread call causes a segfault.

What to use instead of getpass (and why is getpass obsolete)? [duplicate]

I could use getpass() to get a password. However, the man page says:
This function is obsolete. Do not use
it.
What is the current way to get a password from the user's terminal without echoing it, in a POSIX-compliant way? [Originally I said "portably", but my intention was to avoid using an obsolete function.]
this should work on linux/macosx, a windows version should use Get/Set ConsoleMode
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
int
main(int argc, char **argv)
{
struct termios oflags, nflags;
char password[64];
/* disabling echo */
tcgetattr(fileno(stdin), &oflags);
nflags = oflags;
nflags.c_lflag &= ~ECHO;
nflags.c_lflag |= ECHONL;
if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0) {
perror("tcsetattr");
return EXIT_FAILURE;
}
printf("password: ");
fgets(password, sizeof(password), stdin);
password[strlen(password) - 1] = 0;
printf("you typed '%s'\n", password);
/* restore terminal */
if (tcsetattr(fileno(stdin), TCSANOW, &oflags) != 0) {
perror("tcsetattr");
return EXIT_FAILURE;
}
return 0;
}
You could use the ncurses library to read from standard input without echoing the results to the screen. (Call noecho() before getting any input). The library has been around for ages and works on a wide variety of platforms (the windows version can be found here)
Even though this is a very old question that has already been answered, here's what I've been using (which is very similar to the accepted answer):
#include <termios.h>
#include <cstdio>
//
// The following is a slightly modifed version taken from:
// http://www.gnu.org/software/libc/manual/html_node/getpass.html
//
ssize_t my_getpass (char *prompt, char **lineptr, size_t *n, FILE *stream)
{
struct termios _old, _new;
int nread;
/* Turn echoing off and fail if we can’t. */
if (tcgetattr (fileno (stream), &_old) != 0)
return -1;
_new = _old;
_new.c_lflag &= ~ECHO;
if (tcsetattr (fileno (stream), TCSAFLUSH, &_new) != 0)
return -1;
/* Display the prompt */
if (prompt)
printf("%s", prompt);
/* Read the password. */
nread = getline (lineptr, n, stream);
/* Remove the carriage return */
if (nread >= 1 && (*lineptr)[nread - 1] == '\n')
{
(*lineptr)[nread-1] = 0;
nread--;
}
printf("\n");
/* Restore terminal. */
(void) tcsetattr (fileno (stream), TCSAFLUSH, &_old);
return nread;
}
//
// Test harness - demonstrate calling my_getpass().
//
int main(int argc, char *argv[])
{
size_t maxlen = 255;
char pwd[maxlen];
char *pPwd = pwd; // <-- haven't figured out how to avoid this.
int count = my_getpass((char*)"Enter Password: ", &pPwd, &maxlen, stdin);
printf("Size of password: %d\nPassword in plaintext: %s\n", count, pwd);
return 0;
}
On windows, you can probably use the SetConsoleMode api, described here.
According to the University of Milwaukee's documentation it is obsolete because:
The getpass() function is not threadsafe because it manipulates
global signal state.
The getpass() function is scheduled to be withdrawn from a future version of the X/Open CAE Specification.
Another simple solution for Windows.
Include "conio.h"
for (;;) {
int c = _getch();
switch (c)
{
case '\r':
case '\n':
case EOF:
_putch('\n');
break;
default:
_putch('*'); //mask
thePassword += char(c);
continue;
}
break;
}

Getting a password in C without using getpass (3)?

I could use getpass() to get a password. However, the man page says:
This function is obsolete. Do not use
it.
What is the current way to get a password from the user's terminal without echoing it, in a POSIX-compliant way? [Originally I said "portably", but my intention was to avoid using an obsolete function.]
this should work on linux/macosx, a windows version should use Get/Set ConsoleMode
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
int
main(int argc, char **argv)
{
struct termios oflags, nflags;
char password[64];
/* disabling echo */
tcgetattr(fileno(stdin), &oflags);
nflags = oflags;
nflags.c_lflag &= ~ECHO;
nflags.c_lflag |= ECHONL;
if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0) {
perror("tcsetattr");
return EXIT_FAILURE;
}
printf("password: ");
fgets(password, sizeof(password), stdin);
password[strlen(password) - 1] = 0;
printf("you typed '%s'\n", password);
/* restore terminal */
if (tcsetattr(fileno(stdin), TCSANOW, &oflags) != 0) {
perror("tcsetattr");
return EXIT_FAILURE;
}
return 0;
}
You could use the ncurses library to read from standard input without echoing the results to the screen. (Call noecho() before getting any input). The library has been around for ages and works on a wide variety of platforms (the windows version can be found here)
Even though this is a very old question that has already been answered, here's what I've been using (which is very similar to the accepted answer):
#include <termios.h>
#include <cstdio>
//
// The following is a slightly modifed version taken from:
// http://www.gnu.org/software/libc/manual/html_node/getpass.html
//
ssize_t my_getpass (char *prompt, char **lineptr, size_t *n, FILE *stream)
{
struct termios _old, _new;
int nread;
/* Turn echoing off and fail if we can’t. */
if (tcgetattr (fileno (stream), &_old) != 0)
return -1;
_new = _old;
_new.c_lflag &= ~ECHO;
if (tcsetattr (fileno (stream), TCSAFLUSH, &_new) != 0)
return -1;
/* Display the prompt */
if (prompt)
printf("%s", prompt);
/* Read the password. */
nread = getline (lineptr, n, stream);
/* Remove the carriage return */
if (nread >= 1 && (*lineptr)[nread - 1] == '\n')
{
(*lineptr)[nread-1] = 0;
nread--;
}
printf("\n");
/* Restore terminal. */
(void) tcsetattr (fileno (stream), TCSAFLUSH, &_old);
return nread;
}
//
// Test harness - demonstrate calling my_getpass().
//
int main(int argc, char *argv[])
{
size_t maxlen = 255;
char pwd[maxlen];
char *pPwd = pwd; // <-- haven't figured out how to avoid this.
int count = my_getpass((char*)"Enter Password: ", &pPwd, &maxlen, stdin);
printf("Size of password: %d\nPassword in plaintext: %s\n", count, pwd);
return 0;
}
On windows, you can probably use the SetConsoleMode api, described here.
According to the University of Milwaukee's documentation it is obsolete because:
The getpass() function is not threadsafe because it manipulates
global signal state.
The getpass() function is scheduled to be withdrawn from a future version of the X/Open CAE Specification.
Another simple solution for Windows.
Include "conio.h"
for (;;) {
int c = _getch();
switch (c)
{
case '\r':
case '\n':
case EOF:
_putch('\n');
break;
default:
_putch('*'); //mask
thePassword += char(c);
continue;
}
break;
}

Resources