1 /*
2  *    Copyright (c) 2017, The OpenThread Authors.
3  *    All rights reserved.
4  *
5  *    Redistribution and use in source and binary forms, with or without
6  *    modification, are permitted provided that the following conditions are met:
7  *    1. Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *    2. Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *    3. Neither the name of the copyright holder nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  *    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  *    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  *    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20  *    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  *    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  *    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  *    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  *    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #define _GNU_SOURCE 1
29 
30 #ifndef HAVE_CONFIG_H
31 #define HAVE_CONFIG_H 0
32 #endif
33 
34 #if HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37 
38 #include <assert.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <getopt.h>
42 #include <signal.h>
43 #include <stdbool.h>
44 #include <stdint.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <syslog.h>
49 #include <unistd.h>
50 
51 #include <sys/file.h>
52 #include <sys/ioctl.h>
53 #include <sys/select.h>
54 #include <sys/types.h>
55 #include <sys/ucontext.h>
56 
57 #include <linux/ioctl.h>
58 #include <linux/spi/spidev.h>
59 
60 #ifndef HAVE_EXECINFO_H
61 #define HAVE_EXECINFO_H 0
62 #endif
63 
64 #if HAVE_EXECINFO_H
65 #include <execinfo.h>
66 #endif
67 
68 #ifndef HAVE_PTY_H
69 #define HAVE_PTY_H 0
70 #endif
71 
72 #if HAVE_PTY_H
73 #include <pty.h>
74 #endif
75 
76 #ifndef HAVE_UTIL_H
77 #define HAVE_UTIL_H 0
78 #endif
79 
80 #if HAVE_UTIL_H
81 #include <util.h>
82 #endif
83 
84 #ifndef HAVE_OPENPTY
85 #define HAVE_OPENPTY 0
86 #endif
87 
88 /* ------------------------------------------------------------------------- */
89 /* MARK: Macros and Constants */
90 
91 #define SPI_HDLC_VERSION "0.07"
92 
93 #define MAX_FRAME_SIZE 2048
94 #define HEADER_LEN 5
95 #define SPI_HEADER_RESET_FLAG 0x80
96 #define SPI_HEADER_CRC_FLAG 0x40
97 #define SPI_HEADER_PATTERN_VALUE 0x02
98 #define SPI_HEADER_PATTERN_MASK 0x03
99 
100 #define EXIT_QUIT 65535
101 
102 #ifndef MSEC_PER_SEC
103 #define MSEC_PER_SEC 1000
104 #endif
105 
106 #ifndef USEC_PER_MSEC
107 #define USEC_PER_MSEC 1000
108 #endif
109 
110 #ifndef USEC_PER_SEC
111 #define USEC_PER_SEC (USEC_PER_MSEC * MSEC_PER_SEC)
112 #endif
113 
114 #define SPI_POLL_PERIOD_MSEC (MSEC_PER_SEC / 30)
115 
116 #define IMMEDIATE_RETRY_COUNT 5
117 #define FAST_RETRY_COUNT 15
118 
119 #define IMMEDIATE_RETRY_TIMEOUT_MSEC 1
120 #define FAST_RETRY_TIMEOUT_MSEC 10
121 #define SLOW_RETRY_TIMEOUT_MSEC 33
122 
123 #define GPIO_INT_ASSERT_STATE 0 // I̅N̅T̅ is asserted low
124 #define GPIO_RES_ASSERT_STATE 0 // R̅E̅S̅ is asserted low
125 
126 #define SPI_RX_ALIGN_ALLOWANCE_MAX 16
127 
128 #define SOCKET_DEBUG_BYTES_PER_LINE 16
129 
130 #ifndef AUTO_PRINT_BACKTRACE
131 #define AUTO_PRINT_BACKTRACE (HAVE_EXECINFO_H)
132 #endif
133 
134 #define AUTO_PRINT_BACKTRACE_STACK_DEPTH 20
135 
136 static const uint8_t  kHdlcResetSignal[] = {0x7E, 0x13, 0x11, 0x7E};
137 static const uint16_t kHdlcCrcCheckValue = 0xf0b8;
138 static const uint16_t kHdlcCrcResetValue = 0xffff;
139 
140 enum
141 {
142     MODE_STDIO = 0,
143     MODE_PTY   = 1,
144 };
145 
146 // Ignores return value from function 's'
147 #define IGNORE_RETURN_VALUE(s) \
148     do                         \
149     {                          \
150         if (s)                 \
151         {                      \
152         }                      \
153     } while (0)
154 
155 /* ------------------------------------------------------------------------- */
156 /* MARK: Global State */
157 
158 #if HAVE_OPENPTY
159 static int sMode = MODE_PTY;
160 #else
161 static int sMode = MODE_STDIO;
162 #endif
163 
164 static int sLogLevel = LOG_WARNING;
165 
166 static int sSpiDevFd       = -1;
167 static int sResGpioValueFd = -1;
168 static int sIntGpioValueFd = -1;
169 
170 static int sHdlcInputFd  = -1;
171 static int sHdlcOutputFd = -1;
172 
173 static int     sSpiSpeed      = 1000000; // in Hz (default: 1MHz)
174 static uint8_t sSpiMode       = 0;
175 static int     sSpiCsDelay    = 20; // in microseconds
176 static int     sSpiResetDelay = 0;  // in milliseconds
177 
178 static uint16_t sSpiRxPayloadSize;
179 static uint8_t  sSpiRxFrameBuffer[MAX_FRAME_SIZE + SPI_RX_ALIGN_ALLOWANCE_MAX];
180 
181 static uint16_t sSpiTxPayloadSize;
182 static bool     sSpiTxIsReady      = false;
183 static int      sSpiTxRefusedCount = 0;
184 static uint8_t  sSpiTxFrameBuffer[MAX_FRAME_SIZE + SPI_RX_ALIGN_ALLOWANCE_MAX];
185 
186 static int sSpiRxAlignAllowance = 0;
187 static int sSpiSmallPacketSize  = 32; // in bytes
188 
189 static bool sSlaveDidReset = false;
190 
191 static int sCaughtSignal = -1;
192 
193 // If sUseRawFrames is set to true, HDLC encoding/encoding
194 // is skipped and the raw frames are read-from/written-to
195 // the sHdlcInputFd/sHdlcOutputFd whole. See `--raw`.
196 static bool sUseRawFrames = false;
197 
198 static int sMTU = MAX_FRAME_SIZE - HEADER_LEN;
199 
200 static int sRet = 0;
201 
202 static bool sDumpStats = false;
203 
204 static sig_t sPreviousHandlerForSIGINT;
205 static sig_t sPreviousHandlerForSIGTERM;
206 
207 /* ------------------------------------------------------------------------- */
208 /* MARK: Statistics */
209 
210 static uint64_t sSlaveResetCount           = 0;
211 static uint64_t sSpiFrameCount             = 0;
212 static uint64_t sSpiValidFrameCount        = 0;
213 static uint64_t sSpiGarbageFrameCount      = 0;
214 static uint64_t sSpiDuplexFrameCount       = 0;
215 static uint64_t sSpiUnresponsiveFrameCount = 0;
216 static uint64_t sHdlcRxFrameByteCount      = 0;
217 static uint64_t sHdlcTxFrameByteCount      = 0;
218 static uint64_t sHdlcRxFrameCount          = 0;
219 static uint64_t sHdlcTxFrameCount          = 0;
220 static uint64_t sHdlcRxBadCrcCount         = 0;
221 
222 /* ------------------------------------------------------------------------- */
223 /* MARK: Signal Handlers */
224 
signal_SIGINT(int sig)225 static void signal_SIGINT(int sig)
226 {
227     static const char message[] = "\nCaught SIGINT!\n";
228 
229     sRet = EXIT_QUIT;
230 
231     // Can't use syslog() because it isn't async signal safe.
232     // So we write to stderr
233     IGNORE_RETURN_VALUE(write(STDERR_FILENO, message, sizeof(message) - 1));
234     sCaughtSignal = sig;
235 
236     // Restore the previous handler so that if we end up getting
237     // this signal again we perform the system default action.
238     signal(SIGINT, sPreviousHandlerForSIGINT);
239     sPreviousHandlerForSIGINT = NULL;
240 
241     // Ignore signal argument.
242     (void)sig;
243 }
244 
signal_SIGTERM(int sig)245 static void signal_SIGTERM(int sig)
246 {
247     static const char message[] = "\nCaught SIGTERM!\n";
248 
249     sRet = EXIT_QUIT;
250 
251     // Can't use syslog() because it isn't async signal safe.
252     // So we write to stderr
253     IGNORE_RETURN_VALUE(write(STDERR_FILENO, message, sizeof(message) - 1));
254     sCaughtSignal = sig;
255 
256     // Restore the previous handler so that if we end up getting
257     // this signal again we perform the system default action.
258     signal(SIGTERM, sPreviousHandlerForSIGTERM);
259     sPreviousHandlerForSIGTERM = NULL;
260 
261     // Ignore signal argument.
262     (void)sig;
263 }
264 
signal_SIGHUP(int sig)265 static void signal_SIGHUP(int sig)
266 {
267     static const char message[] = "\nCaught SIGHUP!\n";
268 
269     sRet = EXIT_FAILURE;
270 
271     // Can't use syslog() because it isn't async signal safe.
272     // So we write to stderr
273     IGNORE_RETURN_VALUE(write(STDERR_FILENO, message, sizeof(message) - 1));
274     sCaughtSignal = sig;
275 
276     // We don't restore the "previous handler"
277     // because we always want to let the main
278     // loop decide what to do for hangups.
279 
280     // Ignore signal argument.
281     (void)sig;
282 }
283 
signal_dumpstats(int sig)284 static void signal_dumpstats(int sig)
285 {
286     sDumpStats = true;
287 
288     // Ignore signal argument.
289     (void)sig;
290 }
291 
signal_clearstats(int sig)292 static void signal_clearstats(int sig)
293 {
294     sDumpStats                 = true;
295     sSlaveResetCount           = 0;
296     sSpiFrameCount             = 0;
297     sSpiValidFrameCount        = 0;
298     sSpiGarbageFrameCount      = 0;
299     sSpiDuplexFrameCount       = 0;
300     sSpiUnresponsiveFrameCount = 0;
301     sHdlcRxFrameByteCount      = 0;
302     sHdlcTxFrameByteCount      = 0;
303     sHdlcRxFrameCount          = 0;
304     sHdlcTxFrameCount          = 0;
305     sHdlcRxBadCrcCount         = 0;
306 
307     // Ignore signal argument.
308     (void)sig;
309 }
310 
311 #if AUTO_PRINT_BACKTRACE
signal_critical(int sig,siginfo_t * info,void * ucontext)312 static void signal_critical(int sig, siginfo_t *info, void *ucontext)
313 {
314     // This is the last hurah for this process.
315     // We dump the stack, because that's all we can do.
316 
317     void       *stack_mem[AUTO_PRINT_BACKTRACE_STACK_DEPTH];
318     void      **stack = stack_mem;
319     char      **stack_symbols;
320     int         stack_depth, i;
321     ucontext_t *uc = (ucontext_t *)ucontext;
322 
323     // Shut up compiler warning.
324     (void)uc;
325     (void)info;
326 
327     // We call some functions here which aren't async-signal-safe,
328     // but this function isn't really useful without those calls.
329     // Since we are making a gamble (and we deadlock if we loose),
330     // we are going to set up a two-second watchdog to make sure
331     // we end up terminating like we should. The choice of a two
332     // second timeout is entirely arbitrary, and may be changed
333     // if needs warrant.
334     alarm(2);
335     signal(SIGALRM, SIG_DFL);
336 
337     fprintf(stderr, " *** FATAL ERROR: Caught signal %d (%s):\n", sig, strsignal(sig));
338 
339     stack_depth = backtrace(stack, AUTO_PRINT_BACKTRACE_STACK_DEPTH);
340 
341     // Here are are trying to update the pointer in the backtrace
342     // to be the actual location of the fault.
343 #if defined(__x86_64__)
344     stack[1] = (void *)uc->uc_mcontext.gregs[REG_RIP];
345 #elif defined(__i386__)
346     stack[1] = (void *)uc->uc_mcontext.gregs[REG_EIP];
347 #elif defined(__arm__)
348     stack[1] = (void *)uc->uc_mcontext.arm_ip;
349 #else
350 #warning TODO: Add this arch to signal_critical
351 #endif
352 
353     // Now dump the symbols to stderr, in case syslog barfs.
354     backtrace_symbols_fd(stack, stack_depth, STDERR_FILENO);
355 
356     // Load up the symbols individually, so we can output to syslog, too.
357     stack_symbols = backtrace_symbols(stack, stack_depth);
358 
359     syslog(LOG_CRIT, " *** FATAL ERROR: Caught signal %d (%s):", sig, strsignal(sig));
360 
361     for (i = 0; i != stack_depth; i++)
362     {
363         syslog(LOG_CRIT, "[BT] %2d: %s", i, stack_symbols[i]);
364     }
365 
366     free(stack_symbols);
367 
368     exit(EXIT_FAILURE);
369 }
370 #endif // if AUTO_PRINT_BACKTRACE
371 
log_debug_buffer(const char * desc,const uint8_t * buffer_ptr,int buffer_len,bool force)372 static void log_debug_buffer(const char *desc, const uint8_t *buffer_ptr, int buffer_len, bool force)
373 {
374     int i = 0;
375 
376     if (!force && (sLogLevel < LOG_DEBUG))
377     {
378         return;
379     }
380 
381     while (i < buffer_len)
382     {
383         int  j;
384         char dump_string[SOCKET_DEBUG_BYTES_PER_LINE * 3 + 1];
385 
386         for (j = 0; i < buffer_len && j < SOCKET_DEBUG_BYTES_PER_LINE; i++, j++)
387         {
388             sprintf(dump_string + j * 3, "%02X ", buffer_ptr[i]);
389         }
390 
391         syslog(force ? LOG_WARNING : LOG_DEBUG, "%s: %s%s", desc, dump_string, (i < buffer_len) ? " ..." : "");
392     }
393 }
394 
395 /* ------------------------------------------------------------------------- */
396 /* MARK: SPI Transfer Functions */
397 
spi_header_set_flag_byte(uint8_t * header,uint8_t value)398 static void spi_header_set_flag_byte(uint8_t *header, uint8_t value) { header[0] = value; }
399 
spi_header_set_accept_len(uint8_t * header,uint16_t len)400 static void spi_header_set_accept_len(uint8_t *header, uint16_t len)
401 {
402     header[1] = ((len >> 0) & 0xFF);
403     header[2] = ((len >> 8) & 0xFF);
404 }
405 
spi_header_set_data_len(uint8_t * header,uint16_t len)406 static void spi_header_set_data_len(uint8_t *header, uint16_t len)
407 {
408     header[3] = ((len >> 0) & 0xFF);
409     header[4] = ((len >> 8) & 0xFF);
410 }
411 
spi_header_get_flag_byte(const uint8_t * header)412 static uint8_t spi_header_get_flag_byte(const uint8_t *header) { return header[0]; }
413 
spi_header_get_accept_len(const uint8_t * header)414 static uint16_t spi_header_get_accept_len(const uint8_t *header) { return (header[1] + (uint16_t)(header[2] << 8)); }
415 
spi_header_get_data_len(const uint8_t * header)416 static uint16_t spi_header_get_data_len(const uint8_t *header) { return (header[3] + (uint16_t)(header[4] << 8)); }
417 
get_real_rx_frame_start(void)418 static uint8_t *get_real_rx_frame_start(void)
419 {
420     uint8_t *ret = sSpiRxFrameBuffer;
421     int      i   = 0;
422 
423     for (i = 0; i < sSpiRxAlignAllowance; i++)
424     {
425         if (ret[0] != 0xFF)
426         {
427             break;
428         }
429         ret++;
430     }
431 
432     return ret;
433 }
434 
do_spi_xfer(int len)435 static int do_spi_xfer(int len)
436 {
437     int ret;
438 
439     struct spi_ioc_transfer xfer[2] = {{
440                                            // This part is the delay between C̅S̅ being
441                                            // asserted and the SPI clock starting. This
442                                            // is not supported by all Linux SPI drivers.
443                                            .tx_buf        = 0,
444                                            .rx_buf        = 0,
445                                            .len           = 0,
446                                            .delay_usecs   = (uint16_t)sSpiCsDelay,
447                                            .speed_hz      = (uint32_t)sSpiSpeed,
448                                            .bits_per_word = 8,
449                                            .cs_change     = false,
450                                        },
451                                        {
452                                            // This part is the actual SPI transfer.
453                                            .tx_buf        = (unsigned long)sSpiTxFrameBuffer,
454                                            .rx_buf        = (unsigned long)sSpiRxFrameBuffer,
455                                            .len           = (uint32_t)(len + HEADER_LEN + sSpiRxAlignAllowance),
456                                            .delay_usecs   = 0,
457                                            .speed_hz      = (uint32_t)sSpiSpeed,
458                                            .bits_per_word = 8,
459                                            .cs_change     = false,
460                                        }};
461 
462     if (sSpiCsDelay > 0)
463     {
464         // A C̅S̅ delay has been specified. Start transactions
465         // with both parts.
466         ret = ioctl(sSpiDevFd, SPI_IOC_MESSAGE(2), &xfer[0]);
467     }
468     else
469     {
470         // No C̅S̅ delay has been specified, so we skip the first
471         // part because it causes some SPI drivers to croak.
472         ret = ioctl(sSpiDevFd, SPI_IOC_MESSAGE(1), &xfer[1]);
473     }
474 
475     if (ret != -1)
476     {
477         log_debug_buffer("SPI-TX", sSpiTxFrameBuffer, (int)xfer[1].len, false);
478         log_debug_buffer("SPI-RX", sSpiRxFrameBuffer, (int)xfer[1].len, false);
479 
480         sSpiFrameCount++;
481     }
482 
483     return ret;
484 }
485 
debug_spi_header(const char * hint,bool force)486 static void debug_spi_header(const char *hint, bool force)
487 {
488     if (force || (sLogLevel >= LOG_DEBUG))
489     {
490         const uint8_t *spiRxFrameBuffer = get_real_rx_frame_start();
491 
492         syslog(force ? LOG_WARNING : LOG_DEBUG, "%s-TX: H:%02X ACCEPT:%d DATA:%0d\n", hint,
493                spi_header_get_flag_byte(sSpiTxFrameBuffer), spi_header_get_accept_len(sSpiTxFrameBuffer),
494                spi_header_get_data_len(sSpiTxFrameBuffer));
495 
496         syslog(force ? LOG_WARNING : LOG_DEBUG, "%s-RX: H:%02X ACCEPT:%d DATA:%0d\n", hint,
497                spi_header_get_flag_byte(spiRxFrameBuffer), spi_header_get_accept_len(spiRxFrameBuffer),
498                spi_header_get_data_len(spiRxFrameBuffer));
499     }
500 }
501 
push_pull_spi(void)502 static int push_pull_spi(void)
503 {
504     int            ret;
505     uint16_t       spi_xfer_bytes   = 0;
506     const uint8_t *spiRxFrameBuffer = NULL;
507     uint8_t        slave_header;
508     uint16_t       slave_max_rx;
509     int            successful_exchanges = 0;
510 
511     static uint16_t slave_data_len;
512 
513     // For now, sSpiRxPayloadSize must be zero
514     // when entering this function. This may change
515     // at some point, for now this makes things
516     // much easier.
517     assert(sSpiRxPayloadSize == 0);
518 
519     if (sSpiValidFrameCount == 0)
520     {
521         // Set the reset flag to indicate to our slave that we
522         // are coming up from scratch.
523         spi_header_set_flag_byte(sSpiTxFrameBuffer, SPI_HEADER_RESET_FLAG | SPI_HEADER_PATTERN_VALUE);
524     }
525     else
526     {
527         spi_header_set_flag_byte(sSpiTxFrameBuffer, SPI_HEADER_PATTERN_VALUE);
528     }
529 
530     // Zero out our rx_accept and our data_len for now.
531     spi_header_set_accept_len(sSpiTxFrameBuffer, 0);
532     spi_header_set_data_len(sSpiTxFrameBuffer, 0);
533 
534     // Sanity check.
535     if (slave_data_len > MAX_FRAME_SIZE)
536     {
537         slave_data_len = 0;
538     }
539 
540     if (sSpiTxIsReady)
541     {
542         // Go ahead and try to immediately send a frame if we have it queued up.
543         spi_header_set_data_len(sSpiTxFrameBuffer, sSpiTxPayloadSize);
544 
545         if (sSpiTxPayloadSize > spi_xfer_bytes)
546         {
547             spi_xfer_bytes = sSpiTxPayloadSize;
548         }
549     }
550 
551     if (sSpiRxPayloadSize == 0)
552     {
553         if (slave_data_len != 0)
554         {
555             // In a previous transaction the slave indicated
556             // it had something to send us. Make sure our
557             // transaction is large enough to handle it.
558             if (slave_data_len > spi_xfer_bytes)
559             {
560                 spi_xfer_bytes = slave_data_len;
561             }
562         }
563         else
564         {
565             // Set up a minimum transfer size to allow small
566             // frames the slave wants to send us to be handled
567             // in a single transaction.
568             if (sSpiSmallPacketSize > spi_xfer_bytes)
569             {
570                 spi_xfer_bytes = (uint16_t)sSpiSmallPacketSize;
571             }
572         }
573 
574         spi_header_set_accept_len(sSpiTxFrameBuffer, spi_xfer_bytes);
575     }
576 
577     // Perform the SPI transaction.
578     ret = do_spi_xfer(spi_xfer_bytes);
579 
580     if (ret < 0)
581     {
582         perror("push_pull_spi:do_spi_xfer");
583         syslog(LOG_ERR, "push_pull_spi:do_spi_xfer: errno=%d (%s)", errno, strerror(errno));
584 
585         // Print out a helpful error message for
586         // a common error.
587         if ((sSpiCsDelay != 0) && (errno == EINVAL))
588         {
589             syslog(LOG_ERR, "SPI ioctl failed with EINVAL. Try adding `--spi-cs-delay=0` to command line arguments.");
590         }
591         goto bail;
592     }
593 
594     // Account for misalignment (0xFF bytes at the start)
595     spiRxFrameBuffer = get_real_rx_frame_start();
596 
597     debug_spi_header("push_pull", false);
598 
599     slave_header = spi_header_get_flag_byte(spiRxFrameBuffer);
600 
601     if ((slave_header == 0xFF) || (slave_header == 0x00))
602     {
603         if ((slave_header == spiRxFrameBuffer[1]) && (slave_header == spiRxFrameBuffer[2]) &&
604             (slave_header == spiRxFrameBuffer[3]) && (slave_header == spiRxFrameBuffer[4]))
605         {
606             // Device is off or in a bad state.
607             // In some cases may be induced by flow control.
608             syslog(slave_data_len == 0 ? LOG_DEBUG : LOG_WARNING,
609                    "Slave did not respond to frame. (Header was all 0x%02X)", slave_header);
610             sSpiUnresponsiveFrameCount++;
611         }
612         else
613         {
614             // Header is full of garbage
615             syslog(LOG_WARNING, "Garbage in header : %02X %02X %02X %02X %02X", spiRxFrameBuffer[0],
616                    spiRxFrameBuffer[1], spiRxFrameBuffer[2], spiRxFrameBuffer[3], spiRxFrameBuffer[4]);
617             sSpiGarbageFrameCount++;
618             if (sLogLevel < LOG_DEBUG)
619             {
620                 log_debug_buffer("SPI-TX", sSpiTxFrameBuffer, (int)spi_xfer_bytes + HEADER_LEN + sSpiRxAlignAllowance,
621                                  true);
622                 log_debug_buffer("SPI-RX", sSpiRxFrameBuffer, (int)spi_xfer_bytes + HEADER_LEN + sSpiRxAlignAllowance,
623                                  true);
624             }
625         }
626         sSpiTxRefusedCount++;
627         goto bail;
628     }
629 
630     slave_max_rx   = spi_header_get_accept_len(spiRxFrameBuffer);
631     slave_data_len = spi_header_get_data_len(spiRxFrameBuffer);
632 
633     if (((slave_header & SPI_HEADER_PATTERN_MASK) != SPI_HEADER_PATTERN_VALUE) || (slave_max_rx > MAX_FRAME_SIZE) ||
634         (slave_data_len > MAX_FRAME_SIZE))
635     {
636         sSpiGarbageFrameCount++;
637         sSpiTxRefusedCount++;
638         slave_data_len = 0;
639         syslog(LOG_WARNING, "Garbage in header : %02X %02X %02X %02X %02X", spiRxFrameBuffer[0], spiRxFrameBuffer[1],
640                spiRxFrameBuffer[2], spiRxFrameBuffer[3], spiRxFrameBuffer[4]);
641         if (sLogLevel < LOG_DEBUG)
642         {
643             log_debug_buffer("SPI-TX", sSpiTxFrameBuffer, (int)spi_xfer_bytes + HEADER_LEN + sSpiRxAlignAllowance,
644                              true);
645             log_debug_buffer("SPI-RX", sSpiRxFrameBuffer, (int)spi_xfer_bytes + HEADER_LEN + sSpiRxAlignAllowance,
646                              true);
647         }
648         goto bail;
649     }
650 
651     sSpiValidFrameCount++;
652 
653     if ((slave_header & SPI_HEADER_RESET_FLAG) == SPI_HEADER_RESET_FLAG)
654     {
655         sSlaveResetCount++;
656         syslog(LOG_NOTICE, "Slave did reset (%llu resets so far)", (unsigned long long)sSlaveResetCount);
657         sSlaveDidReset = true;
658         sDumpStats     = true;
659     }
660 
661     // Handle received packet, if any.
662     if ((sSpiRxPayloadSize == 0) && (slave_data_len != 0) &&
663         (slave_data_len <= spi_header_get_accept_len(sSpiTxFrameBuffer)))
664     {
665         // We have received a packet. Set sSpiRxPayloadSize so that
666         // the packet will eventually get queued up by push_hdlc().
667         sSpiRxPayloadSize = slave_data_len;
668 
669         slave_data_len = 0;
670 
671         successful_exchanges++;
672     }
673 
674     // Handle transmitted packet, if any.
675     if (sSpiTxIsReady && (sSpiTxPayloadSize == spi_header_get_data_len(sSpiTxFrameBuffer)))
676     {
677         if (spi_header_get_data_len(sSpiTxFrameBuffer) <= slave_max_rx)
678         {
679             // Our outbound packet has been successfully transmitted. Clear
680             // sSpiTxPayloadSize and sSpiTxIsReady so that pull_hdlc() can
681             // pull another packet for us to send.
682             sSpiTxIsReady      = false;
683             sSpiTxPayloadSize  = 0;
684             sSpiTxRefusedCount = 0;
685             successful_exchanges++;
686         }
687         else
688         {
689             // The slave Wasn't ready for what we had to
690             // send them. Incrementing this counter will
691             // turn on rate limiting so that we
692             // don't waste a ton of CPU bombarding them
693             // with useless SPI transfers.
694             sSpiTxRefusedCount++;
695         }
696     }
697 
698     if (!sSpiTxIsReady)
699     {
700         sSpiTxRefusedCount = 0;
701     }
702 
703     if (successful_exchanges == 2)
704     {
705         sSpiDuplexFrameCount++;
706     }
707 bail:
708     return ret;
709 }
710 
check_and_clear_interrupt(void)711 static bool check_and_clear_interrupt(void)
712 {
713     if (sIntGpioValueFd >= 0)
714     {
715         char    value[5] = "";
716         ssize_t len;
717 
718         lseek(sIntGpioValueFd, 0, SEEK_SET);
719 
720         len = read(sIntGpioValueFd, value, sizeof(value) - 1);
721 
722         if (len < 0)
723         {
724             perror("check_and_clear_interrupt");
725             sRet = EXIT_FAILURE;
726         }
727 
728         // The interrupt pin is active low.
729         return GPIO_INT_ASSERT_STATE == atoi(value);
730     }
731 
732     return true;
733 }
734 
735 /* ------------------------------------------------------------------------- */
736 /* MARK: HDLC Transfer Functions */
737 
738 #define HDLC_BYTE_FLAG 0x7E
739 #define HDLC_BYTE_ESC 0x7D
740 #define HDLC_BYTE_XON 0x11
741 #define HDLC_BYTE_XOFF 0x13
742 #define HDLC_BYTE_SPECIAL 0xF8
743 #define HDLC_ESCAPE_XFORM 0x20
744 
hdlc_crc16(uint16_t aFcs,uint8_t aByte)745 static uint16_t hdlc_crc16(uint16_t aFcs, uint8_t aByte)
746 {
747 #if 1
748     // CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-CCITT
749     // width=16 poly=0x1021 init=0x0000 refin=true refout=true xorout=0x0000 check=0x2189 name="KERMIT"
750     // http://reveng.sourceforge.net/crc-catalogue/16.htm#crc.cat.kermit
751     static const uint16_t sFcsTable[256] = {
752         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5,
753         0xe97e, 0xf8f7, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 0x9cc9, 0x8d40, 0xbfdb, 0xae52,
754         0xdaed, 0xcb64, 0xf9ff, 0xe876, 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a, 0xbcc3,
755         0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
756         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9,
757         0x2732, 0x36bb, 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 0x5285, 0x430c, 0x7197, 0x601e,
758         0x14a1, 0x0528, 0x37b3, 0x263a, 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 0x6306, 0x728f,
759         0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
760         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862,
761         0x9af9, 0x8b70, 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840, 0x19c9, 0x2b52, 0x3adb,
762         0x4e64, 0x5fed, 0x6d76, 0x7cff, 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x18c1, 0x0948,
763         0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
764         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226,
765         0xd0bd, 0xc134, 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c, 0xd785, 0xe51e, 0xf497,
766         0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0xd68d, 0xc704,
767         0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
768         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb,
769         0x0e70, 0x1ff9, 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, 0x6a4e, 0x58d5, 0x495c,
770         0x3de3, 0x2c6a, 0x1ef1, 0x0f78};
771     return (aFcs >> 8) ^ sFcsTable[(aFcs ^ aByte) & 0xff];
772 #else
773     // CRC-16/CCITT-FALSE, same CRC as 802.15.4
774     // width=16 poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000 check=0x29b1 name="CRC-16/CCITT-FALSE"
775     // http://reveng.sourceforge.net/crc-catalogue/16.htm#crc.cat.crc-16-ccitt-false
776     aFcs = (uint16_t)((aFcs >> 8) | (aFcs << 8));
777     aFcs ^= aByte;
778     aFcs ^= ((aFcs & 0xff) >> 4);
779     aFcs ^= (aFcs << 12);
780     aFcs ^= ((aFcs & 0xff) << 5);
781     return aFcs;
782 #endif
783 }
784 
hdlc_byte_needs_escape(uint8_t byte)785 static bool hdlc_byte_needs_escape(uint8_t byte)
786 {
787     switch (byte)
788     {
789     case HDLC_BYTE_SPECIAL:
790     case HDLC_BYTE_ESC:
791     case HDLC_BYTE_FLAG:
792     case HDLC_BYTE_XOFF:
793     case HDLC_BYTE_XON:
794         return true;
795 
796     default:
797         return false;
798     }
799 }
800 
push_hdlc(void)801 static int push_hdlc(void)
802 {
803     int             ret              = 0;
804     const uint8_t  *spiRxFrameBuffer = get_real_rx_frame_start();
805     static uint8_t  escaped_frame_buffer[MAX_FRAME_SIZE * 2];
806     static uint16_t unescaped_frame_len;
807     static uint16_t escaped_frame_len;
808     static uint16_t escaped_frame_sent;
809 
810     if (escaped_frame_len == 0)
811     {
812         if (sSlaveDidReset)
813         {
814             // Indicate an MCU reset.
815             memcpy(escaped_frame_buffer, kHdlcResetSignal, sizeof(kHdlcResetSignal));
816             escaped_frame_len = sizeof(kHdlcResetSignal);
817             sSlaveDidReset    = false;
818 
819             // Set this to zero, since this isn't a real frame.
820             unescaped_frame_len = 0;
821         }
822         else if (sSpiRxPayloadSize != 0)
823         {
824             // Escape the frame.
825             uint8_t  c;
826             uint16_t fcs = kHdlcCrcResetValue;
827             uint16_t i;
828 
829             unescaped_frame_len = sSpiRxPayloadSize;
830 
831             for (i = 0; i < sSpiRxPayloadSize; i++)
832             {
833                 c   = spiRxFrameBuffer[i + HEADER_LEN];
834                 fcs = hdlc_crc16(fcs, c);
835                 if (hdlc_byte_needs_escape(c))
836                 {
837                     escaped_frame_buffer[escaped_frame_len++] = HDLC_BYTE_ESC;
838                     escaped_frame_buffer[escaped_frame_len++] = c ^ HDLC_ESCAPE_XFORM;
839                 }
840                 else
841                 {
842                     escaped_frame_buffer[escaped_frame_len++] = c;
843                 }
844             }
845 
846             fcs ^= 0xFFFF;
847 
848             c = fcs & 0xFF;
849             if (hdlc_byte_needs_escape(c))
850             {
851                 escaped_frame_buffer[escaped_frame_len++] = HDLC_BYTE_ESC;
852                 escaped_frame_buffer[escaped_frame_len++] = c ^ HDLC_ESCAPE_XFORM;
853             }
854             else
855             {
856                 escaped_frame_buffer[escaped_frame_len++] = c;
857             }
858 
859             c = (fcs >> 8) & 0xFF;
860             if (hdlc_byte_needs_escape(c))
861             {
862                 escaped_frame_buffer[escaped_frame_len++] = HDLC_BYTE_ESC;
863                 escaped_frame_buffer[escaped_frame_len++] = c ^ HDLC_ESCAPE_XFORM;
864             }
865             else
866             {
867                 escaped_frame_buffer[escaped_frame_len++] = c;
868             }
869 
870             escaped_frame_buffer[escaped_frame_len++] = HDLC_BYTE_FLAG;
871             escaped_frame_sent                        = 0;
872             sSpiRxPayloadSize                         = 0;
873         }
874         else
875         {
876             // Nothing to do.
877             goto bail;
878         }
879     }
880 
881     ret = (int)write(sHdlcOutputFd, escaped_frame_buffer + escaped_frame_sent, escaped_frame_len - escaped_frame_sent);
882 
883     if (ret < 0)
884     {
885         if (errno == EAGAIN)
886         {
887             ret = 0;
888         }
889         else
890         {
891             perror("push_hdlc:write");
892             syslog(LOG_ERR, "push_hdlc:write: errno=%d (%s)", errno, strerror(errno));
893         }
894         goto bail;
895     }
896 
897     escaped_frame_sent += ret;
898 
899     // Reset state once we have sent the entire frame.
900     if (escaped_frame_len == escaped_frame_sent)
901     {
902         escaped_frame_len = escaped_frame_sent = 0;
903 
904         // Increment counter for statistics
905         sHdlcTxFrameCount++;
906         sHdlcTxFrameByteCount += unescaped_frame_len;
907     }
908 
909     ret = 0;
910 
911 bail:
912     return ret;
913 }
914 
pull_hdlc(void)915 static int pull_hdlc(void)
916 {
917     int             ret = 0;
918     static uint16_t fcs;
919     static bool     unescape_next_byte = false;
920 
921     if (!sSpiTxIsReady)
922     {
923         uint8_t byte;
924         while ((ret = (int)read(sHdlcInputFd, &byte, 1)) == 1)
925         {
926             if (sSpiTxPayloadSize >= (MAX_FRAME_SIZE - HEADER_LEN))
927             {
928                 syslog(LOG_WARNING, "HDLC frame was too big");
929                 unescape_next_byte = false;
930                 sSpiTxPayloadSize  = 0;
931                 fcs                = kHdlcCrcResetValue;
932             }
933             else if (byte == HDLC_BYTE_FLAG)
934             {
935                 if (sSpiTxPayloadSize <= 2)
936                 {
937                     unescape_next_byte = false;
938                     sSpiTxPayloadSize  = 0;
939                     fcs                = kHdlcCrcResetValue;
940                     continue;
941                 }
942                 else if (fcs != kHdlcCrcCheckValue)
943                 {
944                     syslog(LOG_WARNING, "HDLC frame with bad CRC (LEN:%d, FCS:0x%04X)", sSpiTxPayloadSize, fcs);
945                     sHdlcRxBadCrcCount++;
946                     unescape_next_byte = false;
947                     sSpiTxPayloadSize  = 0;
948                     fcs                = kHdlcCrcResetValue;
949                     continue;
950                 }
951 
952                 // Clip off the CRC
953                 sSpiTxPayloadSize -= 2;
954 
955                 // Indicate that a frame is ready to go out
956                 sSpiTxIsReady = true;
957 
958                 // Increment counters for statistics
959                 sHdlcRxFrameCount++;
960                 sHdlcRxFrameByteCount += sSpiTxPayloadSize;
961 
962                 // Clean up for the next frame
963                 unescape_next_byte = false;
964                 fcs                = kHdlcCrcResetValue;
965                 break;
966             }
967             else if (byte == HDLC_BYTE_ESC)
968             {
969                 unescape_next_byte = true;
970                 continue;
971             }
972             else if (hdlc_byte_needs_escape(byte))
973             {
974                 // Skip all other control codes.
975                 continue;
976             }
977             else if (unescape_next_byte)
978             {
979                 byte               = byte ^ HDLC_ESCAPE_XFORM;
980                 unescape_next_byte = false;
981             }
982 
983             fcs                                                 = hdlc_crc16(fcs, byte);
984             sSpiTxFrameBuffer[HEADER_LEN + sSpiTxPayloadSize++] = byte;
985         }
986     }
987 
988     if (ret < 0)
989     {
990         if (errno == EAGAIN)
991         {
992             ret = 0;
993         }
994         else
995         {
996             perror("pull_hdlc:read");
997             syslog(LOG_ERR, "pull_hdlc:read: errno=%d (%s)", errno, strerror(errno));
998         }
999     }
1000 
1001     return ret < 0 ? ret : 0;
1002 }
1003 
1004 /* ------------------------------------------------------------------------- */
1005 /* MARK: Raw Transfer Functions */
1006 
push_raw(void)1007 static int push_raw(void)
1008 {
1009     int             ret              = 0;
1010     const uint8_t  *spiRxFrameBuffer = get_real_rx_frame_start();
1011     static uint8_t  raw_frame_buffer[MAX_FRAME_SIZE];
1012     static uint16_t raw_frame_len;
1013     static uint16_t raw_frame_sent;
1014 
1015     if (raw_frame_len == 0)
1016     {
1017         if (sSlaveDidReset)
1018         {
1019             // Indicates an MCU reset.
1020             // We don't have anything to do here because
1021             // raw mode doesn't have any way to signal
1022             // resets out-of-band.
1023             sSlaveDidReset = false;
1024         }
1025         else if (sSpiRxPayloadSize > 0)
1026         {
1027             // Read the frame into raw_frame_buffer
1028             assert(sSpiRxPayloadSize <= sizeof(raw_frame_buffer));
1029             memcpy(raw_frame_buffer, &spiRxFrameBuffer[HEADER_LEN], sSpiRxPayloadSize);
1030             raw_frame_len     = sSpiRxPayloadSize;
1031             raw_frame_sent    = 0;
1032             sSpiRxPayloadSize = 0;
1033         }
1034         else
1035         {
1036             // Nothing to do.
1037             goto bail;
1038         }
1039     }
1040 
1041     ret = (int)write(sHdlcOutputFd, raw_frame_buffer + raw_frame_sent, raw_frame_len - raw_frame_sent);
1042 
1043     if (ret < 0)
1044     {
1045         if (errno == EAGAIN)
1046         {
1047             ret = 0;
1048         }
1049         else
1050         {
1051             perror("push_raw:write");
1052             syslog(LOG_ERR, "push_raw:write: errno=%d (%s)", errno, strerror(errno));
1053         }
1054         goto bail;
1055     }
1056 
1057     raw_frame_sent += ret;
1058 
1059     // Reset state once we have sent the entire frame.
1060     if (raw_frame_len == raw_frame_sent)
1061     {
1062         // Increment counter for statistics
1063         sHdlcTxFrameCount++;
1064         sHdlcTxFrameByteCount += raw_frame_len;
1065 
1066         raw_frame_len = raw_frame_sent = 0;
1067     }
1068 
1069     ret = 0;
1070 
1071 bail:
1072     return ret;
1073 }
1074 
pull_raw(void)1075 static int pull_raw(void)
1076 {
1077     int ret = 0;
1078 
1079     if (!sSpiTxIsReady)
1080     {
1081         ret = (int)read(sHdlcInputFd, &sSpiTxFrameBuffer[HEADER_LEN], (size_t)sMTU);
1082 
1083         if (ret < 0)
1084         {
1085             if (errno == EAGAIN)
1086             {
1087                 ret = 0;
1088             }
1089             else
1090             {
1091                 perror("pull_raw:read");
1092                 syslog(LOG_ERR, "pull_raw:read: errno=%d (%s)", errno, strerror(errno));
1093             }
1094         }
1095         else if (ret > 0)
1096         {
1097             sSpiTxPayloadSize = (uint16_t)ret;
1098             sSpiTxIsReady     = true;
1099 
1100             // Increment counters for statistics
1101             sHdlcRxFrameCount++;
1102             sHdlcRxFrameByteCount += sSpiTxPayloadSize;
1103         }
1104     }
1105 
1106     return ret < 0 ? ret : 0;
1107 }
1108 
1109 /* ------------------------------------------------------------------------- */
1110 /* MARK: Setup Functions */
1111 
update_spi_mode(int x)1112 static bool update_spi_mode(int x)
1113 {
1114     sSpiMode = (uint8_t)x;
1115 
1116     if ((sSpiDevFd >= 0) && (ioctl(sSpiDevFd, SPI_IOC_WR_MODE, &sSpiMode) < 0))
1117     {
1118         perror("ioctl(SPI_IOC_WR_MODE)");
1119         return false;
1120     }
1121 
1122     return true;
1123 }
1124 
update_spi_speed(int x)1125 static bool update_spi_speed(int x)
1126 {
1127     sSpiSpeed = x;
1128 
1129     if ((sSpiDevFd >= 0) && (ioctl(sSpiDevFd, SPI_IOC_WR_MAX_SPEED_HZ, &sSpiSpeed) < 0))
1130     {
1131         perror("ioctl(SPI_IOC_WR_MAX_SPEED_HZ)");
1132         return false;
1133     }
1134 
1135     return true;
1136 }
1137 
setup_spi_dev(const char * path)1138 static bool setup_spi_dev(const char *path)
1139 {
1140     int           fd            = -1;
1141     const uint8_t spi_word_bits = 8;
1142     int           ret;
1143 
1144     syslog(LOG_DEBUG, "SPI device path: %s", path);
1145 
1146     fd = open(path, O_RDWR | O_CLOEXEC);
1147     if (fd < 0)
1148     {
1149         perror("open");
1150         goto bail;
1151     }
1152 
1153     // Set the SPI mode.
1154     ret = ioctl(fd, SPI_IOC_WR_MODE, &sSpiMode);
1155     if (ret < 0)
1156     {
1157         perror("ioctl(SPI_IOC_WR_MODE)");
1158         goto bail;
1159     }
1160 
1161     // Set the SPI clock speed.
1162     ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &sSpiSpeed);
1163     if (ret < 0)
1164     {
1165         perror("ioctl(SPI_IOC_WR_MAX_SPEED_HZ)");
1166         goto bail;
1167     }
1168 
1169     // Set the SPI word size.
1170     ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &spi_word_bits);
1171     if (ret < 0)
1172     {
1173         perror("ioctl(SPI_IOC_WR_BITS_PER_WORD)");
1174         goto bail;
1175     }
1176 
1177     // Lock the file descriptor
1178     if (flock(fd, LOCK_EX | LOCK_NB) < 0)
1179     {
1180         perror("flock");
1181         goto bail;
1182     }
1183 
1184     sSpiDevFd = fd;
1185     fd        = -1;
1186 
1187 bail:
1188     if (fd >= 0)
1189     {
1190         close(fd);
1191     }
1192     return sSpiDevFd >= 0;
1193 }
1194 
setup_res_gpio(const char * path)1195 static bool setup_res_gpio(const char *path)
1196 {
1197     int   setup_fd   = -1;
1198     char *dir_path   = NULL;
1199     char *value_path = NULL;
1200     int   len;
1201 
1202     syslog(LOG_DEBUG, "Reset gpio path: %s", path);
1203 
1204     len = asprintf(&dir_path, "%s/direction", path);
1205 
1206     if (len < 0)
1207     {
1208         perror("asprintf");
1209         goto bail;
1210     }
1211 
1212     len = asprintf(&value_path, "%s/value", path);
1213 
1214     if (len < 0)
1215     {
1216         perror("asprintf");
1217         goto bail;
1218     }
1219 
1220     setup_fd = open(dir_path, O_WRONLY | O_CLOEXEC);
1221 
1222     if (setup_fd >= 0)
1223     {
1224         if (-1 == write(setup_fd, "high\n", 5))
1225         {
1226             perror("set_res_direction");
1227             goto bail;
1228         }
1229     }
1230 
1231     sResGpioValueFd = open(value_path, O_WRONLY | O_CLOEXEC);
1232 
1233 bail:
1234 
1235     if (setup_fd >= 0)
1236     {
1237         close(setup_fd);
1238     }
1239 
1240     if (dir_path)
1241     {
1242         free(dir_path);
1243     }
1244 
1245     if (value_path)
1246     {
1247         free(value_path);
1248     }
1249 
1250     return sResGpioValueFd >= 0;
1251 }
1252 
trigger_reset(void)1253 static void trigger_reset(void)
1254 {
1255     if (sResGpioValueFd >= 0)
1256     {
1257         char str[] = {'0' + GPIO_RES_ASSERT_STATE, '\n'};
1258 
1259         lseek(sResGpioValueFd, 0, SEEK_SET);
1260         if (write(sResGpioValueFd, str, sizeof(str)) == -1)
1261         {
1262             syslog(LOG_ERR, "trigger_reset(): error on write: %d (%s)", errno, strerror(errno));
1263         }
1264 
1265         usleep(10 * USEC_PER_MSEC);
1266 
1267         // Set the string to switch to the not-asserted state.
1268         str[0] = '0' + !GPIO_RES_ASSERT_STATE;
1269 
1270         lseek(sResGpioValueFd, 0, SEEK_SET);
1271         if (write(sResGpioValueFd, str, sizeof(str)) == -1)
1272         {
1273             syslog(LOG_ERR, "trigger_reset(): error on write: %d (%s)", errno, strerror(errno));
1274         }
1275 
1276         syslog(LOG_NOTICE, "Triggered hardware reset");
1277     }
1278 }
1279 
setup_int_gpio(const char * path)1280 static bool setup_int_gpio(const char *path)
1281 {
1282     char   *edge_path  = NULL;
1283     char   *dir_path   = NULL;
1284     char   *value_path = NULL;
1285     ssize_t len;
1286     int     setup_fd = -1;
1287 
1288     sIntGpioValueFd = -1;
1289 
1290     syslog(LOG_DEBUG, "Interrupt gpio path: %s", path);
1291 
1292     len = asprintf(&dir_path, "%s/direction", path);
1293 
1294     if (len < 0)
1295     {
1296         perror("asprintf");
1297         goto bail;
1298     }
1299 
1300     len = asprintf(&edge_path, "%s/edge", path);
1301 
1302     if (len < 0)
1303     {
1304         perror("asprintf");
1305         goto bail;
1306     }
1307 
1308     len = asprintf(&value_path, "%s/value", path);
1309 
1310     if (len < 0)
1311     {
1312         perror("asprintf");
1313         goto bail;
1314     }
1315 
1316     setup_fd = open(dir_path, O_WRONLY | O_CLOEXEC);
1317 
1318     if (setup_fd >= 0)
1319     {
1320         len = write(setup_fd, "in", 2);
1321         if (len < 0)
1322         {
1323             perror("write");
1324             goto bail;
1325         }
1326 
1327         close(setup_fd);
1328     }
1329 
1330     setup_fd = open(edge_path, O_WRONLY | O_CLOEXEC);
1331 
1332     if (setup_fd >= 0)
1333     {
1334         len = write(setup_fd, "falling", 7);
1335 
1336         if (len < 0)
1337         {
1338             perror("write");
1339             goto bail;
1340         }
1341 
1342         close(setup_fd);
1343 
1344         setup_fd = -1;
1345     }
1346 
1347     sIntGpioValueFd = open(value_path, O_RDONLY | O_CLOEXEC);
1348 
1349 bail:
1350 
1351     if (setup_fd >= 0)
1352     {
1353         close(setup_fd);
1354     }
1355 
1356     if (edge_path)
1357     {
1358         free(edge_path);
1359     }
1360 
1361     if (dir_path)
1362     {
1363         free(dir_path);
1364     }
1365 
1366     if (value_path)
1367     {
1368         free(value_path);
1369     }
1370 
1371     return sIntGpioValueFd >= 0;
1372 }
1373 
1374 /* ------------------------------------------------------------------------- */
1375 /* MARK: Help */
1376 
print_version(void)1377 static void print_version(void)
1378 {
1379     printf("spi-hdlc-adapter " SPI_HDLC_VERSION " (" __TIME__ " " __DATE__ ")\n");
1380     printf("Copyright (c) 2017 The OpenThread Authors, All Rights Reserved\n");
1381 }
1382 
print_help(void)1383 static void print_help(void)
1384 {
1385     print_version();
1386     const char *help = "\n"
1387                        "Syntax:\n"
1388                        "\n"
1389                        "    spi-hdlc [options] <spi-device-path>\n"
1390                        "\n"
1391                        "Options:\n"
1392                        "\n"
1393                        "    --stdio ...................... Use `stdin` and `stdout` for HDLC input and\n"
1394                        "                                   output. Useful when directly started by the\n"
1395                        "                                   program that will be using it.\n"
1396 #if HAVE_OPENPTY
1397                        "    --pty ........................ Create a pseudoterminal for HDLC input and\n"
1398                        "                                   output. The path of the newly-created PTY\n"
1399                        "                                   will be written to `stdout`, followed by a\n"
1400                        "                                   newline.\n"
1401 #endif // HAVE_OPENPTY
1402                        "    --raw ........................ Do not encode/decode packets using HDLC.\n"
1403                        "                                   Instead, write whole, raw frames to the\n"
1404                        "                                   specified input and output FDs. This is useful\n"
1405                        "                                   for emulating a serial port, or when datagram-\n"
1406                        "                                   based sockets are supplied for stdin and\n"
1407                        "                                   stdout` (when used with --stdio).\n"
1408                        "    --mtu=[MTU] .................. Specify the MTU. Currently only used in raw mode.\n"
1409                        "                                   Default and maximum value is 2043.\n"
1410                        "    -i/--gpio-int[=gpio-path] .... Specify a path to the Linux sysfs-exported\n"
1411                        "                                   GPIO directory for the `I̅N̅T̅` pin. If not\n"
1412                        "                                   specified, `spi-hdlc` will fall back to\n"
1413                        "                                   polling, which is inefficient.\n"
1414                        "    -r/--gpio-reset[=gpio-path] .. Specify a path to the Linux sysfs-exported\n"
1415                        "                                   GPIO directory for the `R̅E̅S̅` pin.\n"
1416                        "    --spi-mode[=mode] ............ Specify the SPI mode to use (0-3).\n"
1417                        "    --spi-speed[=hertz] .......... Specify the SPI speed in hertz.\n"
1418                        "    --spi-cs-delay[=usec] ........ Specify the delay after C̅S̅ assertion, in µsec\n"
1419                        "    --spi-reset-delay[=ms] ....... Specify the delay after R̅E̅S̅E̅T̅ assertion, in milliseconds\n"
1420                        "    --spi-align-allowance[=n] .... Specify the maximum number of 0xFF bytes to\n"
1421                        "                                   clip from start of MISO frame. Max value is 16.\n"
1422                        "    --spi-small-packet=[n] ....... Specify the smallest packet we can receive\n"
1423                        "                                   in a single transaction(larger packets will\n"
1424                        "                                   require two transactions). Default value is 32.\n"
1425                        "    -v/--verbose[=num] ............Change log verbosity level. (Repeatable)\n"
1426                        "                                   num argument is optional and value 1 is default\n"
1427                        "                                   when not specified. Every instance of this option\n"
1428                        "                                   will increment or decrement (when num is negative)\n"
1429                        "                                   the syslog log level accordingly. Starting default\n"
1430                        "                                   log level is LOG_NOTICE (5).\n"
1431                        "    -h/-?/--help ................. Print out usage information and exit.\n"
1432                        "\n";
1433 
1434     printf("%s", help);
1435 }
1436 
log_level_to_str(int log_level)1437 static const char *log_level_to_str(int log_level)
1438 {
1439     const char *str;
1440 
1441     switch (log_level)
1442     {
1443     case LOG_EMERG:
1444         str = "EMERG";
1445         break;
1446     case LOG_ALERT:
1447         str = "ALERT";
1448         break;
1449     case LOG_CRIT:
1450         str = "CRIT";
1451         break;
1452     case LOG_ERR:
1453         str = "ERR";
1454         break;
1455     case LOG_WARNING:
1456         str = "WARNING";
1457         break;
1458     case LOG_NOTICE:
1459         str = "NOTICE";
1460         break;
1461     case LOG_INFO:
1462         str = "INFO";
1463         break;
1464     case LOG_DEBUG:
1465         str = "DEBUG";
1466         break;
1467     default:
1468         str = "-unknown-";
1469         break;
1470     }
1471 
1472     return str;
1473 }
1474 
1475 /* ------------------------------------------------------------------------- */
1476 /* MARK: Main Loop */
1477 
main(int argc,char * argv[])1478 int main(int argc, char *argv[])
1479 {
1480     int            i = 0;
1481     char           prog[32];
1482     static fd_set  read_set;
1483     static fd_set  write_set;
1484     static fd_set  error_set;
1485     struct timeval timeout;
1486     int            max_fd                   = -1;
1487     bool           did_print_rate_limit_log = false;
1488 
1489 #if AUTO_PRINT_BACKTRACE
1490     struct sigaction sigact;
1491 #endif // if AUTO_PRINT_BACKTRACE
1492 
1493     enum
1494     {
1495         ARG_SPI_MODE            = 1001,
1496         ARG_SPI_SPEED           = 1002,
1497         ARG_VERBOSE             = 1003,
1498         ARG_SPI_CS_DELAY        = 1004,
1499         ARG_SPI_ALIGN_ALLOWANCE = 1005,
1500         ARG_RAW                 = 1006,
1501         ARG_MTU                 = 1007,
1502         ARG_SPI_SMALL_PACKET    = 1008,
1503         ARG_SPI_RESET_DELAY     = 1009,
1504     };
1505 
1506     static struct option options[] = {
1507         {"stdio", no_argument, &sMode, MODE_STDIO},
1508         {"pty", no_argument, &sMode, MODE_PTY},
1509         {"gpio-int", required_argument, NULL, 'i'},
1510         {"gpio-res", required_argument, NULL, 'r'},
1511         {"verbose", optional_argument, NULL, ARG_VERBOSE},
1512         {"version", no_argument, NULL, 'V'},
1513         {"raw", no_argument, NULL, ARG_RAW},
1514         {"mtu", required_argument, NULL, ARG_MTU},
1515         {"help", no_argument, NULL, 'h'},
1516         {"spi-mode", required_argument, NULL, ARG_SPI_MODE},
1517         {"spi-speed", required_argument, NULL, ARG_SPI_SPEED},
1518         {"spi-cs-delay", required_argument, NULL, ARG_SPI_CS_DELAY},
1519         {"spi-align-allowance", required_argument, NULL, ARG_SPI_ALIGN_ALLOWANCE},
1520         {"spi-small-packet", required_argument, NULL, ARG_SPI_SMALL_PACKET},
1521         {"spi-reset-delay", required_argument, NULL, ARG_SPI_RESET_DELAY},
1522         {NULL, 0, NULL, 0},
1523     };
1524 
1525     strncpy(prog, argv[0], sizeof(prog) - 1);
1526     prog[sizeof(prog) - 1] = 0;
1527 
1528     if (argc < 2)
1529     {
1530         print_help();
1531         exit(EXIT_FAILURE);
1532     }
1533 
1534     // ========================================================================
1535     // INITIALIZATION
1536 
1537     sPreviousHandlerForSIGINT  = signal(SIGINT, &signal_SIGINT);
1538     sPreviousHandlerForSIGTERM = signal(SIGTERM, &signal_SIGTERM);
1539     signal(SIGHUP, &signal_SIGHUP);
1540     signal(SIGUSR1, &signal_dumpstats);
1541     signal(SIGUSR2, &signal_clearstats);
1542 
1543 #if AUTO_PRINT_BACKTRACE
1544     sigact.sa_sigaction = &signal_critical;
1545     sigact.sa_flags     = SA_RESTART | SA_SIGINFO | SA_NOCLDWAIT;
1546 
1547     sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL);
1548     sigaction(SIGBUS, &sigact, (struct sigaction *)NULL);
1549     sigaction(SIGILL, &sigact, (struct sigaction *)NULL);
1550     sigaction(SIGABRT, &sigact, (struct sigaction *)NULL);
1551 #endif // if AUTO_PRINT_BACKTRACE
1552 
1553     // ========================================================================
1554     // ARGUMENT PARSING
1555 
1556     openlog(basename(prog), LOG_PERROR | LOG_PID | LOG_CONS, LOG_DAEMON);
1557 
1558     setlogmask(LOG_UPTO(sLogLevel));
1559 
1560     while (1)
1561     {
1562         int c = getopt_long(argc, argv, "i:r:vVh?", options, NULL);
1563         if (c == -1)
1564         {
1565             break;
1566         }
1567         else
1568         {
1569             switch (c)
1570             {
1571             case 'i':
1572                 if (!setup_int_gpio(optarg))
1573                 {
1574                     syslog(LOG_ERR, "Unable to setup INT GPIO \"%s\", %s", optarg, strerror(errno));
1575                     exit(EXIT_FAILURE);
1576                 }
1577                 break;
1578 
1579             case ARG_SPI_ALIGN_ALLOWANCE:
1580                 assert(optarg);
1581 
1582                 errno                = 0;
1583                 sSpiRxAlignAllowance = atoi(optarg);
1584 
1585                 if (errno != 0 || (sSpiRxAlignAllowance < 0))
1586                 {
1587                     syslog(LOG_ERR, "Invalid SPI RX Align Allowance \"%s\"", optarg);
1588                     exit(EXIT_FAILURE);
1589                 }
1590 
1591                 if (sSpiRxAlignAllowance > SPI_RX_ALIGN_ALLOWANCE_MAX)
1592                 {
1593                     syslog(LOG_WARNING, "Reducing SPI RX Align Allowance from %s to %d", optarg,
1594                            SPI_RX_ALIGN_ALLOWANCE_MAX);
1595                     sSpiRxAlignAllowance = SPI_RX_ALIGN_ALLOWANCE_MAX;
1596                 }
1597 
1598                 break;
1599 
1600             case ARG_SPI_MODE:
1601                 assert(optarg);
1602 
1603                 if (!update_spi_mode(atoi(optarg)))
1604                 {
1605                     syslog(LOG_ERR, "Unable to set SPI mode to \"%s\", %s", optarg, strerror(errno));
1606                     exit(EXIT_FAILURE);
1607                 }
1608                 break;
1609 
1610             case ARG_SPI_SPEED:
1611                 assert(optarg);
1612 
1613                 if (!update_spi_speed(atoi(optarg)))
1614                 {
1615                     syslog(LOG_ERR, "Unable to set SPI speed to \"%s\", %s", optarg, strerror(errno));
1616                     exit(EXIT_FAILURE);
1617                 }
1618                 break;
1619 
1620             case ARG_SPI_SMALL_PACKET:
1621                 assert(optarg);
1622 
1623                 sSpiSmallPacketSize = atoi(optarg);
1624                 if (sSpiSmallPacketSize > MAX_FRAME_SIZE - HEADER_LEN)
1625                 {
1626                     syslog(LOG_WARNING, "Reducing SPI small-packet size from %s to %d", optarg,
1627                            MAX_FRAME_SIZE - HEADER_LEN);
1628                     sSpiSmallPacketSize = MAX_FRAME_SIZE - HEADER_LEN;
1629                 }
1630                 if (sSpiSmallPacketSize < 0)
1631                 {
1632                     syslog(LOG_ERR, "The argument to --spi-small-packet cannot be negative. (Given: \"%s\")", optarg);
1633                     exit(EXIT_FAILURE);
1634                 }
1635                 syslog(LOG_NOTICE, "SPI small-packet size set to %d bytes.", sSpiSmallPacketSize);
1636                 break;
1637 
1638             case ARG_SPI_CS_DELAY:
1639                 assert(optarg);
1640 
1641                 sSpiCsDelay = atoi(optarg);
1642                 if (sSpiCsDelay < 0)
1643                 {
1644                     syslog(LOG_ERR, "Negative values (%d) for --spi-cs-delay are invalid.", sSpiCsDelay);
1645                     exit(EXIT_FAILURE);
1646                 }
1647                 syslog(LOG_NOTICE, "SPI CS Delay set to %d usec", sSpiCsDelay);
1648                 break;
1649 
1650             case ARG_SPI_RESET_DELAY:
1651                 assert(optarg);
1652 
1653                 sSpiResetDelay = atoi(optarg);
1654                 if (sSpiResetDelay < 0)
1655                 {
1656                     syslog(LOG_ERR, "Negative value (%d) for --spi-reset-delay is invalid.", sSpiResetDelay);
1657                     exit(EXIT_FAILURE);
1658                 }
1659                 syslog(LOG_NOTICE, "SPI RESET Delay set to %d ms", sSpiResetDelay);
1660                 break;
1661 
1662             case ARG_RAW:
1663                 sUseRawFrames = true;
1664                 syslog(LOG_NOTICE, "HDLC encoding/decoding disabled. Will use raw frames for input/output.");
1665                 break;
1666 
1667             case ARG_MTU:
1668                 assert(optarg);
1669 
1670                 sMTU = atoi(optarg);
1671                 if (sMTU > MAX_FRAME_SIZE - HEADER_LEN)
1672                 {
1673                     syslog(LOG_ERR, "Specified MTU of %d is too large, maximum is %d bytes.", sMTU,
1674                            MAX_FRAME_SIZE - HEADER_LEN);
1675                     exit(EXIT_FAILURE);
1676                 }
1677                 if (sMTU < 1)
1678                 {
1679                     syslog(LOG_ERR, "Specified MTU of %d is too small, minimum is 1 byte.", sMTU);
1680                     exit(EXIT_FAILURE);
1681                 }
1682                 syslog(LOG_NOTICE, "MTU set to %d bytes", sMTU);
1683                 break;
1684 
1685             case 'r':
1686                 if (!setup_res_gpio(optarg))
1687                 {
1688                     syslog(LOG_ERR, "Unable to setup RES GPIO \"%s\", %s", optarg, strerror(errno));
1689                     exit(EXIT_FAILURE);
1690                 }
1691                 break;
1692 
1693             case 'v':
1694             case ARG_VERBOSE:
1695                 sLogLevel += (optarg != NULL) ? atoi(optarg) : 1;
1696 
1697                 if (sLogLevel > LOG_DEBUG)
1698                 {
1699                     sLogLevel = LOG_DEBUG;
1700                 }
1701 
1702                 if (sLogLevel < LOG_EMERG)
1703                 {
1704                     sLogLevel = LOG_EMERG;
1705                 }
1706 
1707                 setlogmask(LOG_UPTO(sLogLevel));
1708                 syslog(sLogLevel, "Verbosity set to log level %s (%d)", log_level_to_str(sLogLevel), sLogLevel);
1709                 break;
1710 
1711             case 'V':
1712                 print_version();
1713                 exit(EXIT_SUCCESS);
1714                 break;
1715 
1716             case 'h':
1717             case '?':
1718                 print_help();
1719                 exit(EXIT_SUCCESS);
1720                 break;
1721             }
1722         }
1723     }
1724 
1725     syslog(LOG_NOTICE, "spi-hdlc-adapter " SPI_HDLC_VERSION " (" __TIME__ " " __DATE__ ")\n");
1726 
1727     if (optind == argc)
1728     {
1729         fprintf(stderr, "%s: Missing SPI device path\n", prog);
1730         exit(EXIT_FAILURE);
1731     }
1732     else if (optind + 1 == argc)
1733     {
1734         if (!setup_spi_dev(argv[optind]))
1735         {
1736             char spi_path[64];
1737 
1738             strncpy(spi_path, argv[optind], sizeof(spi_path) - 1);
1739             spi_path[sizeof(spi_path) - 1] = 0;
1740             syslog(LOG_ERR, "%s: Unable to open SPI device \"%s\", %s", prog, spi_path, strerror(errno));
1741             exit(EXIT_FAILURE);
1742         }
1743     }
1744     else
1745     {
1746         fprintf(stderr, "%s: Unexpected argument \"%s\"\n", prog, argv[optind + 1]);
1747         exit(EXIT_FAILURE);
1748     }
1749 
1750     if (sMode == MODE_STDIO)
1751     {
1752         sHdlcInputFd  = dup(STDIN_FILENO);
1753         sHdlcOutputFd = dup(STDOUT_FILENO);
1754         close(STDIN_FILENO);
1755         close(STDOUT_FILENO);
1756     }
1757     else if (sMode == MODE_PTY)
1758     {
1759 #if HAVE_OPENPTY
1760 
1761         static int pty_slave_fd = -1;
1762         char       pty_name[1024];
1763         sRet = openpty(&sHdlcInputFd, &pty_slave_fd, pty_name, NULL, NULL);
1764 
1765         if (sRet != 0)
1766         {
1767             perror("openpty");
1768             goto bail;
1769         }
1770 
1771         sHdlcOutputFd = dup(sHdlcInputFd);
1772 
1773         printf("%s\n", pty_name);
1774 
1775         close(STDOUT_FILENO);
1776 
1777 #else // if HAVE_OPENPTY
1778 
1779         syslog(LOG_ERR, "Not built with support for `--pty`.");
1780         sRet = EXIT_FAILURE;
1781         goto bail;
1782 
1783 #endif // else HAVE_OPENPTY
1784     }
1785     else
1786     {
1787         sRet = EXIT_FAILURE;
1788         goto bail;
1789     }
1790 
1791     if ((sHdlcInputFd < 0) || (sHdlcOutputFd < 0))
1792     {
1793         sRet = EXIT_FAILURE;
1794         goto bail;
1795     }
1796 
1797     // Set up sHdlcInputFd for non-blocking I/O
1798     if (-1 == (i = fcntl(sHdlcInputFd, F_GETFL, 0)))
1799     {
1800         i = 0;
1801     }
1802     IGNORE_RETURN_VALUE(fcntl(sHdlcInputFd, F_SETFL, i | O_NONBLOCK));
1803 
1804     // Since there are so few file descriptors in
1805     // this program, we calculate `max_fd` once
1806     // instead of trying to optimize its value
1807     // at every iteration.
1808     max_fd = sHdlcInputFd;
1809 
1810     if (max_fd < sHdlcOutputFd)
1811     {
1812         max_fd = sHdlcOutputFd;
1813     }
1814 
1815     if (max_fd < sIntGpioValueFd)
1816     {
1817         max_fd = sIntGpioValueFd;
1818     }
1819 
1820     if (sIntGpioValueFd < 0)
1821     {
1822         syslog(LOG_WARNING, "Interrupt pin was not set, must poll SPI. Performance will suffer.");
1823     }
1824 
1825     trigger_reset();
1826 
1827     usleep((useconds_t)sSpiResetDelay * USEC_PER_MSEC);
1828 
1829     // ========================================================================
1830     // MAIN LOOP
1831 
1832     while (sRet == 0)
1833     {
1834         int timeout_ms = MSEC_PER_SEC * 60 * 60 * 24; // 24 hours
1835 
1836         FD_ZERO(&read_set);
1837         FD_ZERO(&write_set);
1838         FD_ZERO(&error_set);
1839 
1840         if (!sSpiTxIsReady)
1841         {
1842             FD_SET(sHdlcInputFd, &read_set);
1843         }
1844         else
1845         {
1846             // We have data to send to the slave.
1847             timeout_ms = 0;
1848         }
1849 
1850         if (sSpiRxPayloadSize != 0)
1851         {
1852             // We have data that we are waiting to send out
1853             // of the HDLC descriptor, so we need to wait
1854             // for that to clear out before we can do anything
1855             // else.
1856             FD_SET(sHdlcOutputFd, &write_set);
1857         }
1858         else if (sIntGpioValueFd >= 0)
1859         {
1860             if (check_and_clear_interrupt())
1861             {
1862                 // Interrupt pin is asserted,
1863                 // set the timeout to be 0.
1864                 timeout_ms = 0;
1865 
1866                 syslog(LOG_DEBUG, "Interrupt.");
1867             }
1868             else
1869             {
1870                 // The interrupt pin was not asserted,
1871                 // so we wait for the interrupt pin to
1872                 // be asserted by adding it to the error
1873                 // set.
1874                 FD_SET(sIntGpioValueFd, &error_set);
1875             }
1876         }
1877         else if (timeout_ms > SPI_POLL_PERIOD_MSEC)
1878         {
1879             // In this case we don't have an interrupt, so
1880             // we revert to SPI polling.
1881             timeout_ms = SPI_POLL_PERIOD_MSEC;
1882         }
1883 
1884         if (sDumpStats)
1885         {
1886             timeout_ms = 0;
1887         }
1888 
1889         if (sSpiTxRefusedCount)
1890         {
1891             int min_timeout = 0;
1892 
1893             // We are being rate-limited by the slave. This is
1894             // fairly normal behavior. Based on number of times
1895             // slave has refused a transmission, we apply a
1896             // minimum timeout.
1897 
1898             if (sSpiTxRefusedCount < IMMEDIATE_RETRY_COUNT)
1899             {
1900                 min_timeout = IMMEDIATE_RETRY_TIMEOUT_MSEC;
1901             }
1902             else if (sSpiTxRefusedCount < FAST_RETRY_COUNT)
1903             {
1904                 min_timeout = FAST_RETRY_TIMEOUT_MSEC;
1905             }
1906             else
1907             {
1908                 min_timeout = SLOW_RETRY_TIMEOUT_MSEC;
1909             }
1910 
1911             if (timeout_ms < min_timeout)
1912             {
1913                 timeout_ms = min_timeout;
1914             }
1915 
1916             if (sSpiTxIsReady && !did_print_rate_limit_log && (sSpiTxRefusedCount > 1))
1917             {
1918                 // To avoid printing out this message over and over,
1919                 // we only print it out once the refused count is at
1920                 // two or higher when we actually have something to
1921                 // send the slave. And then, we only print it once.
1922                 syslog(LOG_INFO, "Slave is rate limiting transactions");
1923 
1924                 did_print_rate_limit_log = true;
1925             }
1926 
1927             if (sSpiTxRefusedCount == 30)
1928             {
1929                 // Ua-oh. The slave hasn't given us a chance to send
1930                 // it anything for over thirty frames. If this ever
1931                 // happens, print out a warning to the logs.
1932                 syslog(LOG_WARNING, "Slave seems stuck.");
1933             }
1934 
1935             if (sSpiTxRefusedCount == 100)
1936             {
1937                 // Double ua-oh. The slave hasn't given us a chance
1938                 // to send it anything for over a hundred frames.
1939                 // This almost certainly means that the slave has
1940                 // locked up or gotten into an unrecoverable state.
1941                 // It is not spi-hdlc-adapter's job to identify and
1942                 // reset misbehaving devices (that is handled at a
1943                 // higher level), but we go ahead and log the condition
1944                 // for debugging purposes.
1945                 syslog(LOG_ERR, "Slave seems REALLY stuck.");
1946             }
1947         }
1948         else
1949         {
1950             did_print_rate_limit_log = false;
1951         }
1952 
1953         // Calculate the timeout value.
1954         timeout.tv_sec  = timeout_ms / MSEC_PER_SEC;
1955         timeout.tv_usec = (timeout_ms % MSEC_PER_SEC) * USEC_PER_MSEC;
1956 
1957         // Wait for something to happen.
1958         IGNORE_RETURN_VALUE(select(max_fd + 1, &read_set, &write_set, &error_set, &timeout));
1959 
1960         if (sDumpStats || sRet != 0)
1961         {
1962             sDumpStats = false;
1963             syslog(LOG_NOTICE, "INFO: sSlaveResetCount=%llu", (unsigned long long)sSlaveResetCount);
1964             syslog(LOG_NOTICE, "INFO: sSpiFrameCount=%llu", (unsigned long long)sSpiFrameCount);
1965             syslog(LOG_NOTICE, "INFO: sSpiValidFrameCount=%llu", (unsigned long long)sSpiValidFrameCount);
1966             syslog(LOG_NOTICE, "INFO: sSpiDuplexFrameCount=%llu", (unsigned long long)sSpiDuplexFrameCount);
1967             syslog(LOG_NOTICE, "INFO: sSpiUnresponsiveFrameCount=%llu", (unsigned long long)sSpiUnresponsiveFrameCount);
1968             syslog(LOG_NOTICE, "INFO: sSpiGarbageFrameCount=%llu", (unsigned long long)sSpiGarbageFrameCount);
1969             syslog(LOG_NOTICE, "INFO: sHdlcTxFrameCount=%llu", (unsigned long long)sHdlcTxFrameCount);
1970             syslog(LOG_NOTICE, "INFO: sHdlcTxFrameByteCount=%llu", (unsigned long long)sHdlcTxFrameByteCount);
1971             syslog(LOG_NOTICE, "INFO: sHdlcRxFrameCount=%llu", (unsigned long long)sHdlcRxFrameCount);
1972             syslog(LOG_NOTICE, "INFO: sHdlcRxFrameByteCount=%llu", (unsigned long long)sHdlcRxFrameByteCount);
1973             syslog(LOG_NOTICE, "INFO: sHdlcRxBadCrcCount=%llu", (unsigned long long)sHdlcRxBadCrcCount);
1974         }
1975 
1976         // Handle serial input.
1977         if (FD_ISSET(sHdlcInputFd, &read_set))
1978         {
1979             // Read in the data.
1980             if ((sUseRawFrames ? pull_raw() : pull_hdlc()) < 0)
1981             {
1982                 sRet = EXIT_FAILURE;
1983                 break;
1984             }
1985         }
1986 
1987         // Handle serial output.
1988         if (FD_ISSET(sHdlcOutputFd, &write_set))
1989         {
1990             // Write out the data.
1991             if ((sUseRawFrames ? push_raw() : push_hdlc()) < 0)
1992             {
1993                 sRet = EXIT_FAILURE;
1994                 break;
1995             }
1996 
1997             continue;
1998         }
1999 
2000         // Service the SPI port if we can receive
2001         // a packet or we have a packet to be sent.
2002         if ((sSpiRxPayloadSize == 0) && (sSpiTxIsReady || check_and_clear_interrupt()))
2003         {
2004             // We guard this with the above check because we don't
2005             // want to overwrite any previously received (but not
2006             // yet pushed out) frames.
2007             if (push_pull_spi() < 0)
2008             {
2009                 sRet = EXIT_FAILURE;
2010             }
2011         }
2012     }
2013 
2014     // ========================================================================
2015     // SHUTDOWN
2016 
2017 bail:
2018     if (sCaughtSignal != -1)
2019     {
2020         syslog(LOG_ERR, "Caught %s", strsignal(sCaughtSignal));
2021     }
2022 
2023     syslog(LOG_NOTICE, "Shutdown. (sRet = %d)", sRet);
2024 
2025     syslog(LOG_NOTICE, "Reset NCP/RCP");
2026     trigger_reset();
2027 
2028     if (sRet == EXIT_QUIT)
2029     {
2030         sRet = EXIT_SUCCESS;
2031     }
2032     else if (sRet == -1)
2033     {
2034         sRet = EXIT_FAILURE;
2035     }
2036 
2037     return sRet;
2038 }
2039