2 * mshell.c: A modem shell program.
4 * (yet another small minicom-like program which will become bloat over the
7 * TODO (to make bloat):
9 * 1- Would be cool to have support for internal commands
10 * (eg, to set new memory size);
12 * 2- read_response() sets the timeout using SIGALRM, would be
13 * simpler/better to use select() instead;
15 * 3- Would be good to catch some signals (eg, SIGINT).
17 * 4- The end of input at read_response() is too simple.
19 * Luiz Fernando N. Capitulino
20 * <lcapitulino@gmail.com>
31 #include <sys/types.h>
32 #include <readline/readline.h>
33 #include <readline/history.h>
35 #define MODEM_TIMEOUT 7 /* XXX: Random number */
36 #define DEFAULT_BUFFER 1024
38 static volatile sig_atomic_t timeout
;
40 static void handler(int signum
)
48 * read_response - Reads a modem response
50 * @param fd Modem's file-descriptor
51 * @param buf Buffer to store the response
52 * @param buf_len 'buf' length
54 * @return 0 on success, -1 otherwise
56 static int read_response(int fd
, char *buf
, size_t buf_len
)
62 struct sigaction
new, old
;
64 if (fd
< 0 || !buf
|| !buf_len
) {
69 new.sa_handler
= handler
;
70 sigemptyset(&new.sa_mask
);
75 err
= sigaction(SIGALRM
, &new, &old
);
79 memset(buf
, '\0', buf_len
);
81 len
= buf_len
-1; /* Forces '\0' */
86 rbytes
= read(fd
, p
, len
);
97 if (strstr(buf
, "\r\nOK\r\n"))
100 if (strstr(buf
, "\r\nERROR\r\n"))
104 if (p
>= (buf
+ buf_len
-1)) {
116 sigaction(SIGALRM
, &old
, NULL
);
121 * open_tty - Opens the modem port
123 * Note: All termios settings was taken from 'Advanced programming in the
124 * Unix Environment' book p. 608.
126 * @param tty_port modem's tty port absolute path
128 * @return file decriptor on success, -1 otherwise
130 static int open_tty(const char *tty_port
)
133 int berrno
, err
, fd
= -1;
140 fd
= open(tty_port
, O_RDWR
| O_NOCTTY
);
144 err
= tcgetattr(fd
, &term
);
151 * Ignore BREAK (XXX: why?).
152 * Enable XON/XOFF flow control.
153 * Strip Input to 7 bits (XXX: why?).
154 * Ignore input parity errors (XXX: why?).
155 * (Note: we are disabling the rest of the options)
157 term
.c_iflag
= IGNBRK
| IXOFF
| IXOFF
| ISTRIP
| IGNPAR
;
162 * turn off all output processing.
171 term
.c_cflag
&= ~(CSIZE
);
176 * Sets 8 bits character.
178 * Hang up the modem when last processes closes it.
179 * Ignore modem control lines (it is attached).
181 term
.c_cflag
|= (CS8
| CREAD
| HUPCL
| CLOCAL
);
186 * Everything off: canonical mode, disables signal
187 * generation, disable ECHO.
197 term
.c_cc
[VTIME
] = 0;
199 err
= cfsetispeed(&term
, B115200
);
203 err
= cfsetospeed(&term
, B115200
);
207 err
= tcsetattr(fd
, TCSANOW
, &term
);
210 if (err
&& fd
>= 0) {
221 * __send_command - Sends a command to the modem
223 * @param fd Modem's file-descriptor
224 * @param cmd command to be sent
225 * @param cmd_len 'cmd' length
227 * @return 0 on success, -1 otheriwse
229 static int __send_command(int fd
, char *cmd
, size_t cmd_len
)
235 if (fd
< 0 || !cmd
|| !cmd_len
) {
244 wbytes
= write(fd
, p
, len
);
256 * send_command - Sends a command to the modem
258 * @param fd Modem's file-descriptor
259 * @param cmd command to be sent
261 * @return 0 on success, -1 otheriwse
263 static int send_command(int fd
, char *cmd
)
267 if (fd
< 0 || !cmd
) {
272 err
= __send_command(fd
, cmd
, strlen(cmd
));
276 err
= __send_command(fd
, "\r\n", 2);
283 static void usage(void)
286 "Usage: mshell < port_name > [ -s ] [ < file ]\n"
290 int main(int argc
, char *argv
[])
294 char *cmd
, buf
[DEFAULT_BUFFER
];
296 if (argc
< 2 || argc
> 3) {
297 fprintf(stderr
, "Invalid number of parameters!\n");
303 if (!strcmp(argv
[1], "-s") || !strcmp(argv
[2], "-s")) {
306 fprintf(stderr
, "Error: option not recognized!\n");
312 fd
= open_tty(argv
[1]);
314 perror("Error: cannot open modem's port");
319 printf("\nDefault settings:\n");
320 printf(" response buffer %d bytes\n", DEFAULT_BUFFER
);
321 printf(" modem's timeout in %d seconds\n\n", MODEM_TIMEOUT
);
325 cmd
= readline("mshell> ");
331 err
= send_command(fd
, cmd
);
333 perror("Error: cannot send command");
339 err
= read_response(fd
, buf
, sizeof(buf
));
341 perror("Cannot read response");