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