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