~vdupras/collapseos

ref: ac3629b817115b1af75096856ee9499cfbbd3392 collapseos/tools/common.c -rw-r--r-- 3.9 KiB
ac3629b8Virgil Dupras Make BLK@* and BLK!* into ialiases 1 year, 10 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>

#define BREATHE usleep(2000)
//#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define DEBUG(...)

void mread(int fd, char *s, int count)
{
    while (count) {
        BREATHE;
        while (read(fd, s, 1) == 0) {
            BREATHE;
        }
        s++;
        count--;
    }
}

// Make sure that nothing is waiting in the pipeline
static void mempty(int fd)
{
    char c;
    while (read(fd, &c, 1) == 1) {
        DEBUG("Emptying %d\n", c);
        BREATHE;
    }
}

int mexpect(int fd, unsigned char ec)
{
    unsigned char c;
    mread(fd, &c, 1);
    if (c != ec) {
        fprintf(stderr, "Expected %x but got %x\n", ec, c);
        return 0;
    }
    return 1;
}

void readprompt(int fd)
{
    mexpect(fd, ' ');
    mexpect(fd, 'o');
    mexpect(fd, 'k');
    mexpect(fd, '\r');
    mexpect(fd, '\n');
}

void sendcmd(int fd, char *cmd)
{
    DEBUG("Sending %s\n", cmd);
    char junk[2];
    while (*cmd) {
        DEBUG("W: %d\n", *cmd);
        write(fd, cmd, 1);
        BREATHE;
        read(fd, &junk, 1);
        DEBUG("R: %d\n", *junk);
        cmd++;
        // The other side is sometimes much slower than us and if we don't let
        // it breathe, it can choke.
        BREATHE;
    }
    write(fd, "\r", 1);
    mexpect(fd, '\r');
    mexpect(fd, '\n');
    BREATHE;
}

// Send a cmd and also read the " ok" prompt
void sendcmdp(int fd, char *cmd)
{
    sendcmd(fd, cmd);
    readprompt(fd);
}

// from https://stackoverflow.com/a/6947758
// discussion from https://stackoverflow.com/a/26006680 is interesting,
// but we don't want POSIX compliance.

int set_interface_attribs(int fd, int speed, int parity)
{
    struct termios tty;
    if (tcgetattr (fd, &tty) != 0) {
        fprintf(stderr, "error %d from tcgetattr", errno);
        return -1;
    }

    if (speed) {
        cfsetospeed (&tty, speed);
        cfsetispeed (&tty, speed);
    }

    tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;     // 8-bit chars
    // disable IGNBRK for mismatched speed tests; otherwise receive break
    // as \000 chars
    tty.c_iflag &= ~IGNBRK;         // disable break processing
    tty.c_iflag &= ~ICRNL;          // disable CR->NL mapping
    tty.c_lflag = 0;                // no signaling chars, no echo,
                                    // no canonical processing
    tty.c_oflag = 0;                // no remapping, no delays
    tty.c_cc[VMIN]  = 0;            // read doesn't block
    tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

    tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl

    tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
                                    // enable reading
    tty.c_cflag &= ~(PARENB | PARODD);      // shut off parity
    tty.c_cflag |= parity;
    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CRTSCTS;

    if (tcsetattr (fd, TCSANOW, &tty) != 0) {
        fprintf(stderr, "error %d from tcsetattr", errno);
        return -1;
    }
    return 0;
}

void set_blocking(int fd, int should_block)
{
    struct termios tty;
    memset(&tty, 0, sizeof tty);
    if (tcgetattr (fd, &tty) != 0) {
        fprintf(stderr, "error %d from tggetattr", errno);
        return;
    }

    tty.c_cc[VMIN]  = should_block ? 1 : 0;
    tty.c_cc[VTIME] = 1;            // 0.1 seconds read timeout

    if (tcsetattr (fd, TCSANOW, &tty) != 0) {
        fprintf(stderr, "error %d setting term attributes", errno);
    }
}

int ttyopen(char *devname)
{
    int fd = 0;
    if (strcmp(devname, "-") != 0) {
        fd = open(devname, O_RDWR|O_NOCTTY|O_SYNC);
    }
    set_interface_attribs(fd, 0, 0);
    set_blocking(fd, 0);
    mempty(fd);
    // Communication with device is much more reliable if we
    // begin by sending, asynchronously, a CR to make sure we
    // empty any pending stuff on all sides.
    write(fd, "\r", 1);
    mempty(fd);
    set_blocking(fd, 1);
    return fd;
}