• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2010, Atmel Corporation.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above copyright
9 //       notice, this list of conditions and the following disclaimer in the
10 //       documentation and/or other materials provided with the distribution.
11 //     * Neither the name of Atmel nor the
12 //       names of its contributors may be used to endorse or promote products
13 //       derived from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
19 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <termios.h>
32 #include <time.h>
33 #include <unistd.h>
34 
35 #include "SA_Phys_Linux.h"
36 #include "SHA_Status.h"
37 #include "SHA_TimeUtils.h"
38 #include "Whisper_AccyMain.h"
39 
40 
41 
42 #define MAX_BUF_LEN     512
43 #define M_ONE_BIT       0x7F
44 #define M_ZERO_BIT      0x7D
45 #define OPPBAUD         B230400
46 #define WAKEBAUD        B115200
47 
48 
49 static void configTtyParams();
50 static int8_t setBaudRate(speed_t Inspeed);
51 static int8_t writeToDevice(uint8_t *data, uint8_t len);
52 static int8_t readFromDevice(uint8_t *readBuf, uint16_t readLen,
53                              uint8_t CmdOfset, uint16_t *retBytes);
54 static int8_t sleepDevice(void);
55 static int16_t formatBytes(uint8_t *ByteData, uint8_t *ByteDataRaw,
56                            int16_t lenData);
57 
58 
59 static const char ttyPort[] = "/dev/ttyHS0";
60 static uint8_t readwriteBuf[MAX_BUF_LEN];
61 static uint8_t WakeStr = {0x00};
62 static uint8_t* pWake = &WakeStr;
63 static uint8_t TransmitStr = {0x88};
64 static uint8_t* pTrm = &TransmitStr;
65 static uint8_t CmdStr = {0x77};
66 static uint8_t* pCmd = &CmdStr;
67 static uint8_t SleepStr= {0xCC};
68 static uint8_t InStr[41];
69 static uint8_t* pIStr = InStr;
70 static fd_set readfs;
71 static struct termios termOptions;
72 
73 int ttyFd = -1;
74 
75 
76  /*  Sets up and configures the UART for use */
SHAP_OpenChannel(void)77 int8_t SHAP_OpenChannel(void) {
78     struct termios tty;
79     speed_t speed;
80     struct timespec ts;
81 
82     ttyFd = open(ttyPort, O_RDWR);
83     if (ttyFd == -1) {
84         DBG_ERROR("Error unable to open device: %s", ttyPort);
85         return SHA_COMM_FAIL;
86     }
87 
88     DBG_TRACE("%s opened with port %d", ttyPort, ttyFd);
89     if (tcflush(ttyFd, TCIOFLUSH) == 0) {
90         DBG_TRACE("The input and output queues have been flushed");
91     }
92     else {
93        DBG_ERROR("tcflush() error");
94     }
95 
96     configTtyParams();
97 
98     ts.tv_sec = 0;
99     ts.tv_nsec = MAX_IO_TIMEOUT * 1000000;
100     nanosleep(&ts, NULL);
101 
102     return SHA_SUCCESS;
103 }
104 
105 
106 
SHAP_CloseChannel(void)107 int8_t SHAP_CloseChannel(void) {
108     int8_t ret = sleepDevice();
109     close(ttyFd);
110     return ret;
111 }
112 
SHAP_SendBytes(uint8_t count,uint8_t * buffer)113 int8_t SHAP_SendBytes(uint8_t count, uint8_t *buffer) {
114     uint16_t bytesRead;
115     int8_t i, retVal;
116 
117     if (!count || !buffer) {
118         DBG_ERROR("Bad input");
119         return SHA_BAD_PARAM;
120     }
121 
122     if (tcflush(ttyFd, TCIOFLUSH) == 0) {
123         DBG_TRACE("The input and output queues have been flushed");
124     }
125     else {
126         DBG_ERROR("tcflush() error");
127     }
128 
129     memmove(&buffer[1], buffer, count);
130     buffer[0] = CmdStr;
131 
132     writeToDevice(buffer, count+1);
133 
134     // Read the echo back ...
135     readFromDevice(readwriteBuf, 8*(count+1), 0, &bytesRead);
136 
137     if (tcflush(ttyFd, TCIFLUSH) == 0) {
138        DBG_TRACE("The input queue has been flushed");
139     }
140     else {
141        DBG_ERROR("tcflush() error");
142     }
143 
144     return SHA_SUCCESS;
145 }
146 
147 
SHAP_ReceiveBytes(uint8_t recCommLen,uint8_t * dataBuf)148 int8_t SHAP_ReceiveBytes(uint8_t recCommLen, uint8_t *dataBuf) {
149     struct timespec ts;
150     uint16_t bytesRead;
151     int8_t i,iResVal, cmdLen = recCommLen;
152 
153     if (!recCommLen || !dataBuf) {
154         return SHA_BAD_PARAM;
155     }
156 
157     if (writeToDevice(pTrm, 1) == 1) {
158         DBG_TRACE("Test Write to %s successful", ttyPort);
159     }
160     else {
161         DBG_ERROR("Test Write to %s unsuccessful", ttyPort);
162     }
163 
164     iResVal = readFromDevice(dataBuf, (cmdLen+1)*8, 8, &bytesRead);
165 
166     if (iResVal == SHA_COMM_FAIL) {
167         DBG_ERROR("Read Error unable to read port: %d from device: %s", ttyFd, ttyPort);
168         return SHA_COMM_FAIL;
169     }
170 
171     return SHA_SUCCESS;
172 }
173 
174 
175 
176 
SHAP_CloseFile(void)177 void SHAP_CloseFile(void) {
178     struct timespec ts;
179     close(ttyFd);
180 
181     ts.tv_sec = 0;
182     ts.tv_nsec = MAX_IO_TIMEOUT * 1000000;
183     nanosleep(&ts, NULL);
184 }
185 
186 
187 
188 
189 /*  Reads the message from device. returns NULL if error */
readFromDevice(uint8_t * readBuf,uint16_t readLen,uint8_t CmdOfset,uint16_t * retBytes)190 static int8_t readFromDevice(uint8_t *readBuf, uint16_t readLen,
191                              uint8_t CmdOfset, uint16_t *retBytes) {
192     int8_t goOn = 1;
193     struct timeval Timeout;
194     uint16_t numBytesRead = 0;
195     int retVal;
196     uint16_t i;
197 
198     Timeout.tv_usec = 200000;
199     Timeout.tv_sec = 0;
200     *retBytes = 0;
201 
202     for (i = 0; i < sizeof(readwriteBuf); i++) {
203         readwriteBuf[i]= 0x00;
204     }
205 
206     while (goOn) {
207         FD_SET(ttyFd, &readfs);
208         retVal = select(ttyFd+1, &readfs, NULL, NULL, &Timeout);
209 
210         if (retVal == 0) {
211             DBG_ERROR("Timeout on select() occurred on port %d. Receive <%d> bytes", ttyFd, numBytesRead);
212             if (numBytesRead > 0) {
213                 return SHA_SUCCESS;
214             }
215             else {
216                 return SHA_COMM_FAIL;
217             }
218         }
219 
220         if (retVal < 0 && errno == EINTR) {
221             DBG_ERROR("SELECT returned EINTR ");
222             continue;
223         }
224 
225         if (FD_ISSET(ttyFd, &readfs)) {
226             do {
227                 retVal = read(ttyFd, &readwriteBuf[numBytesRead], MAX_BUF_LEN);
228             } while (retVal < 0 && errno == EINTR);
229 
230             if (retVal > 0) {
231                 numBytesRead += retVal;
232                 *retBytes = numBytesRead;
233 
234                 DBG_TRACE("REQ READ LEN = %d, NUM BYT READ = %d, retVal = %d offset = %d",
235                            readLen, numBytesRead, retVal, CmdOfset);
236 
237                 if (numBytesRead >= (readLen)) {
238                     DBG_TRACE("Read Success");
239                     break;
240                 }
241             }
242         }
243         else {
244             DBG_ERROR("Select Error. ERRNO = %d", errno);
245         }
246     }
247 
248     formatBytes(readBuf, &readwriteBuf[CmdOfset], readLen-CmdOfset);
249 
250     return SHA_SUCCESS;
251 }
252 
253 
254 
255 
256 /* Transmits a message to be sent over tty */
writeToDevice(uint8_t * data,uint8_t len)257 static int8_t writeToDevice(uint8_t *data, uint8_t len) {
258     uint16_t i,j;
259     int nbytes, nwritten;
260     uint8_t *byteptr;
261 
262     // Every byte gets transferred into 8 bytes
263     if (len*8 > MAX_BUF_LEN) {
264         return SHA_COMM_FAIL;
265     }
266 
267     for(i = 0; i < len; i++) {
268         for(j = 0; j < 8; j++) {
269             if (data[i] & (1 << j)) {
270                 readwriteBuf[(i*8)+j] = M_ONE_BIT;
271             }
272             else {
273                 readwriteBuf[(i*8)+j] = M_ZERO_BIT;
274             }
275         }
276     }
277 
278     do {
279         nwritten = write(ttyFd, readwriteBuf, len*8);
280     } while (nwritten < 0 && errno == EINTR);
281 
282     if (nwritten == -1) {
283         DBG_ERROR("Write Failed with errno = %d", errno);
284         return SHA_COMM_FAIL;
285     }
286     else if (nwritten != len*8)   {
287         DBG_ERROR("ERROR. write less than requested<%d>. written: %i",nwritten, len*8);
288     }
289 
290     nbytes = nwritten / 8;
291 
292     return nbytes;
293 }
294 
295 
296 
297 
298 /* Formats the data received from UART to byte data */
formatBytes(uint8_t * ByteData,uint8_t * ByteDataRaw,int16_t lenData)299 static int16_t formatBytes(uint8_t *ByteData, uint8_t *ByteDataRaw,
300                            int16_t lenData) {
301     uint16_t i,j;
302     int16_t retLen = lenData;
303 
304     for(j = 0; j < retLen/8;j++) {
305         for (i = 0; i < 8; i++) {
306             if ((ByteDataRaw[(8 *j)+i] ^ 0x7F) & 0x7C) {
307                 ByteData[j] &= ~(1 << i);
308             }
309             else {
310                 ByteData[j] |= (1 << i);
311             }
312         }
313     }
314 
315     return SHA_SUCCESS;
316 }
317 
318 
319 
320 /* Wakes the device */
SHAP_WakeDevice(void)321 int8_t SHAP_WakeDevice(void) {
322     int iResVal;
323     struct timespec ts;
324     uint16_t bytes_read;
325     uint8_t bytes_written;
326     ssize_t osize;
327 
328     tcflush(ttyFd, TCIOFLUSH);
329 
330     // Set Start Token Speed
331     setBaudRate(WAKEBAUD);
332 
333     // Send Start Token
334     do {
335         osize = write(ttyFd, pWake, 1);
336     } while (osize < 0 && errno == EINTR);
337 
338     if (osize == -1) {
339         DBG_ERROR("Write Failed with errno = %d", errno);
340         return SHA_COMM_FAIL;
341     }
342 
343     ts.tv_sec = 0;
344     ts.tv_nsec = 3000000;
345     nanosleep(&ts, NULL);
346 
347     // set the Baud Rate to Comm speed
348     setBaudRate(OPPBAUD);
349     if (writeToDevice(pTrm, 1) == 1) {
350         DBG_TRACE("Wakeup Write to %s successful", ttyPort);
351     }
352     else {
353         DBG_TRACE("Wakeup Write to %s unsuccessful", ttyPort);
354     }
355 
356 
357     iResVal = readFromDevice(pIStr, 41, 9, &bytes_read);
358 
359     if (iResVal == SHA_COMM_FAIL || bytes_read < 41) {
360         sleepDevice();
361         DBG_ERROR("WakeUp Error unable to read port: %d, Bytes Read = %d", ttyFd, bytes_read);
362         return SHA_COMM_FAIL;
363     }
364 
365     if (tcflush(ttyFd, TCIOFLUSH) == 0) {
366        DBG_TRACE("The input and output queues have been flushed.");
367     }
368     else {
369        DBG_ERROR("tcflush() error");
370     }
371 
372     if (pIStr[0] == 0x04 && pIStr[1] == 0x11) {
373         DBG_TRACE("WakeUp Done");
374         return SHA_SUCCESS;
375     }
376     else {
377         DBG_ERROR("WakeUp Fail");
378         sleepDevice();
379         return SHA_CMD_FAIL;
380     }
381 }
382 
383 
384 
385 /**
386  * Transmits a message to be sent over tty
387  *
388  * \param[out] Success or fail flag
389  * \return status of the operation
390  */
sleepDevice(void)391 static int8_t sleepDevice(void)
392 {
393     uint8_t *byteptr = &SleepStr;
394     ssize_t osize;
395     struct timespec ts;
396     do {
397         osize = write(ttyFd, byteptr, 1);
398     } while (osize < 0 && errno == EINTR);
399 
400     if (osize == -1) {
401         DBG_ERROR("Write Failed errno = %d", errno);
402         return SHA_COMM_FAIL;
403     }
404     ts.tv_sec = 0;
405     ts.tv_nsec = 100000000; // sleep for 100ms
406     nanosleep(&ts, NULL);
407 
408     return SHA_SUCCESS;
409 }
410 
SA_Delay(uint32_t delay)411 void SA_Delay(uint32_t delay)
412 {
413     struct timespec ts;
414 
415     ts.tv_sec = 0;
416     ts.tv_nsec = delay*1000; // convert us to ns
417     nanosleep(&ts, NULL);
418 }
419 
420 /*  Sets the baudrate of the tty port */
setBaudRate(speed_t Inspeed)421 static int8_t setBaudRate(speed_t Inspeed) {
422     int8_t ret;
423 
424     ret = tcgetattr( ttyFd, &termOptions );
425 
426     if (ret == -1) {
427         DBG_ERROR("Error returned by tcgetattr. errno = %d", errno);
428         return SHA_COMM_FAIL;
429     }
430 
431     cfsetospeed(&termOptions, Inspeed);
432     cfsetispeed(&termOptions, Inspeed);
433     ret = tcsetattr(ttyFd, TCSANOW, &termOptions );
434     if (ret == -1) {
435         DBG_ERROR("Error returned by tcsetattr. errno = %d", errno);
436         return SHA_COMM_FAIL;
437     }
438 
439     return SHA_SUCCESS;
440 }
441 
configTtyParams()442 static void configTtyParams()
443 {
444 
445     struct termios tty;
446 
447     // Get the existing options //
448     tcgetattr(ttyFd, &tty);
449 
450     // Reset Control mode to 0. And enable just what you need //
451     tty.c_cflag = 0;
452     tty.c_cflag |= CLOCAL;     // ignore modem control lines //
453     tty.c_cflag |= CREAD;      // enable receiver
454     tty.c_cflag |= CS7;        // use 7 data bits
455     tty.c_cflag &= ~CRTSCTS;   // do not use RTS and CTS handshake
456 
457     tty.c_iflag = INPCK;
458     tty.c_cc[VINTR]    = 0;     // Ctrl-c
459     tty.c_cc[VQUIT]    = 0;     /* Ctrl-\ */
460     tty.c_cc[VERASE]   = 0;     // del
461     tty.c_cc[VKILL]    = 0;     // @
462     tty.c_cc[VEOF]     = 0;     // Ctrl-d
463     tty.c_cc[VTIME]    = 0;     /// inter-character timer unused
464     tty.c_cc[VMIN]     = 1;     // blocking read until 1 character arrives
465     tty.c_cc[VSWTC]    = 0;     // '\0'
466     tty.c_cc[VSTART]   = 0;     // Ctrl-q
467     tty.c_cc[VSTOP]    = 0;     // Ctrl-s
468     tty.c_cc[VSUSP]    = 0;     // Ctrl-z
469     tty.c_cc[VEOL]     = 0;     // '\0'
470     tty.c_cc[VREPRINT] = 0;     // Ctrl-r
471     tty.c_cc[VDISCARD] = 0;     // Ctrl-u
472     tty.c_cc[VWERASE]  = 0;     // Ctrl-w
473     tty.c_cc[VLNEXT]   = 0;     // Ctrl-v
474     tty.c_cc[VEOL2]    = 0;     // '\0'
475 
476 
477     // Reset Input mode to 0. And enalbe just what you need //
478     tty.c_iflag = 0;
479     tty.c_iflag |= IGNBRK;
480     tty.c_iflag |= INPCK;   // Enable input parity checking //
481 
482 
483     // Reset output mode to 0. And enable just what you need //
484     tty.c_oflag = 0;
485 
486     // Reset local mode to 0. And enable just what you need //
487     tty.c_lflag = 0;
488 
489     tcflush(ttyFd, TCIFLUSH);
490     tcsetattr(ttyFd, TCSANOW, &tty);
491 }
492 
493 
494