![]()  | 
![]()  | 
![]()  | 
![]()  | 
Run a script on a device
#include <sys/modem.h>
int modem_script( int fd,
                  struct modem_script* table,
                  speed_t* baud,
                  void (*io)( 
                        char* progress,
                        char* in,
                        char* out ),
                  int (*cancel)(void) );
libc
Use the -l c option to qcc to link against this library. This library is usually included automatically.
![]()  | 
This function is in libc.a, but not in libc.so (in order to save space). | 
The modem_script() function runs the script table on the device associated with the file descriptor fd. The script implements a simple state machine that emits strings and waits for responses.
Each string that's emitted or received is passed to the function io() as follows:
| Call | Description | 
|---|---|
| (*io)(str, 0, 0) | Emitted progress string | 
| (*io)(0, str, 0) | Received string | 
| (*io)(0, 0, str) | Emitted response string | 
This lets an application set up a callback that can display the script's interaction in a status window.
If you provide a cancel function, it's called once each newquiet 1/10 of a second while waiting for input. If this function returns a nonzero value, the read returns immediately with -1 and errno is set to ETIMEDOUT. You can use the cancel function as a callback in a graphical dialer that needs to support a cancel button to stop a script.
The table is an array of modem_script structures that contain the following members:
Here's an example that demonstrates the operation of the script:
/*
 curstate curflags newstate newflags newtimeout 
 newquiet retvalue pattern response
*/
struct modem_script table[] ={
  {1, 0,            1, 0,              2,  5, 0,
   NULL,              "ATZ\\r\\P0a"},
  {1, 0,            2, 0,              30, 5, 0,
   "*ok*",            "ATDT5910934"},
  {2, MODEM_BAUD,   3, MODEM_LASTLINE, 10, 5, 0,
   "*connect*",       NULL},
  {3, 0,            4, 0,              8,  5, 0,
   "*login:*",        "guest"},
  {4, MODEM_NOECHO, 5, 0,              15, 5, 0,
   "*password:*",     "xxxx"},
  {5, 0,            0, 0,              0,  0, 0,
   "*$ *",            NULL},
  {0, 0,            0, 0,              0,  0, 1,
   "*no carrier*",    NULL},
  {0, 0,            0, 0,              0,  0, 2,
   "*no answer*",     NULL},
  {0, 0,            0, 0,              0,  0, 3,
   "*no dialtone*",   NULL},
  {0, 0,            0, 0,              0,  0, 4,
   "*busy*",          NULL},
  { NULL }
};
When this script is passed to modem_script(), the current state is set to 1, and the output is ATZ (the response in the first array element).
While in any state, modem_script() waits for input, matching it against the current state or the wildcard state of 0.
| Input | Action | 
|---|---|
| *ok* | Go to state 2 and emit ATDT1-591-0934. The flags to be used in the new state are set to 0, the quiet time in the new state is set to 5/10 of a second, and the timeout time in the new state is set to 30 seconds. | 
| *no carrier* | Go to state 0 (the termination newstate), return with the contents of retvalue (1). | 
| *no answer* | Go to state 0 (the termination newstate), return with the contents of retvalue (2). | 
| *no dialtone* | Go to state 0 (the termination newstate), return with the contents of retvalue (3). | 
| *busy* | Go to state 0 (the termination newstate), return with the contents of retvalue (4). | 
| Input | Action | 
|---|---|
| *connect* | Go to state 3 and don't emit anything to the device. The flags to be used in the new state are set to MODEM_LASTLINE, the quiet time in the new state is set to 5/10 of a second, and the timeout time in the new state is set to 10 seconds. Since the current flags are MODEM_BAUD, the baud rate is extracted from the connect message. | 
| *no carrier* | Same as previous table | 
| *no answer* | Same as previous table | 
| *no dialtone* | Same as previous table | 
| *busy* | Same as previous table | 
| Input | Action | 
|---|---|
| *login* | Go to state 4 and emit guest. The flags to be used in the new state are set to 0, the quiet time in the new state is set to 5/10 of a second, and the timeout time in the new state is set to 8 seconds. | 
| *no carrier* | Same as previous table | 
| *no answer* | Same as previous table | 
| *no dialtone* | Same as previous table | 
| *busy* | Same as previous table | 
| Input | Action | 
|---|---|
| *password* | Go to state 5 and emit xxxx. The flags to be used in the new state are set to 0, the quiet time in the new state is set to 5/10 of a second, and the timeout time in the new state is set to 15 seconds. Since the current flags are MODEM_NOECHO, the password response xxxx isn't sent to the io() callback. | 
| *no carrier* | Same as previous table | 
| *no answer* | Same as previous table | 
| *no dialtone* | Same as previous table | 
| *busy* | Same as previous table | 
| Input | Action | 
|---|---|
| *$ * | Go to state 0 (the termination newstate), return with the contents of retvalue (0). | 
| *no carrier* | Same as previous table | 
| *no answer* | Same as previous table | 
| *no dialtone* | Same as previous table | 
| *busy* | Same as previous table | 
If you set the flag MODEM_BAUD for a state, then any number embedded in a matching response is extracted and assigned as a number to the baud parameter.
If you don't set the flag MODEM_NOECHO for a state, then all emitted strings are also given to the passed io function as (*io)(0, 0, response).
The retvalue member of a script entry that terminates the script. This will always be a positive number. If modem_script fails, it returns -1 and sets errno.
| Safety: | |
|---|---|
| Cancellation point | Yes | 
| Interrupt handler | No | 
| Signal handler | Read the Caveats | 
| Thread | Read the Caveats | 
Depending on what you do in your cancel function, it might or might not be safe to call modem_script() from a signal handler or a multithreaded program.
modem_open(), modem_read(), modem_write()
![]()  | 
![]()  | 
![]()  | 
![]()  |