Statistics
| Branch: | Tag: | Revision:

amiro-blt / Host / Source / SerialBoot / port / linux / xcptransport.c @ 69661903

History | View | Annotate | Download (14.529 KB)

1
/************************************************************************************//**
2
* \file         port\linux\xcptransport.c
3
* \brief        XCP transport layer interface source file.
4
* \ingroup      SerialBoot
5
* \internal
6
*----------------------------------------------------------------------------------------
7
*                          C O P Y R I G H T
8
*----------------------------------------------------------------------------------------
9
*   Copyright (c) 2014  by Feaser    http://www.feaser.com    All rights reserved
10
*
11
*----------------------------------------------------------------------------------------
12
*                            L I C E N S E
13
*----------------------------------------------------------------------------------------
14
* This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
15
* modify it under the terms of the GNU General Public License as published by the Free
16
* Software Foundation, either version 3 of the License, or (at your option) any later
17
* version.
18
*
19
* OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
20
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
21
* PURPOSE. See the GNU General Public License for more details.
22
*
23
* You should have received a copy of the GNU General Public License along with OpenBLT.
24
* If not, see <http://www.gnu.org/licenses/>.
25
*
26
* A special exception to the GPL is included to allow you to distribute a combined work
27
* that includes OpenBLT without being obliged to provide the source code for any
28
* proprietary components. The exception text is included at the bottom of the license
29
* file <license.html>.
30
*
31
* \endinternal
32
****************************************************************************************/
33

    
34
/****************************************************************************************
35
* Include files
36
****************************************************************************************/
37
#include <assert.h>                                   /* assertion module              */
38
#include <sb_types.h>                                 /* C types                       */
39
#include <stdio.h>                                    /* standard I/O library          */
40
#include <string.h>                                   /* string function definitions   */
41
#include <unistd.h>                                   /* UNIX standard functions       */
42
#include <fcntl.h>                                    /* file control definitions      */
43
#include <errno.h>                                    /* error number definitions      */
44
#include <termios.h>                                  /* POSIX terminal control        */
45

    
46
#include <sys/ioctl.h>
47
#include <sys/types.h>
48
#include <sys/stat.h>
49

    
50
/*
51
#include <sys/socket.h>
52
#include <bluetooth/bluetooth.h>
53
#include <bluetooth/rfcomm.h>
54
*/
55

    
56
#include <sys/time.h>
57

    
58
#include "xcpmaster.h"                                /* XCP master protocol module    */
59
#include "timeutil.h"                                 /* time utility module           */
60

    
61

    
62
/****************************************************************************************
63
* Macro definitions
64
****************************************************************************************/
65
/** \brief Invalid UART device/file handle. */
66
#define UART_INVALID_HANDLE      (-1)
67

    
68
/** \brief maximum number of bytes in a transmit/receive XCP packet in UART. */
69
#define XCP_MASTER_UART_MAX_DATA ((XCP_MASTER_TX_MAX_DATA>XCP_MASTER_RX_MAX_DATA) ? \
70
                                  (XCP_MASTER_TX_MAX_DATA+1) : (XCP_MASTER_RX_MAX_DATA+1))
71

    
72
/** \brief The smallest time in millisecond that the UART is configured for. */
73
#define UART_RX_TIMEOUT_MIN_MS   (100)
74

    
75

    
76
/****************************************************************************************
77
* Function prototypes
78
****************************************************************************************/
79
static speed_t   XcpTransportGetBaudrateMask(sb_uint32 baudrate);
80

    
81

    
82
/****************************************************************************************
83
* Local data declarations
84
****************************************************************************************/
85
static tXcpTransportResponsePacket responsePacket;
86
static sb_int32 hUart = UART_INVALID_HANDLE;
87
static sb_uint8 errorType = -1;
88
//static unsigned char bluetooth_channel = 1;
89

    
90
static sb_char *tcpDevice;
91
static sb_uint32 tcpBaudrate;
92
static sb_uint8 tcpComIsUart;
93

    
94

    
95
/************************************************************************************//**
96
** \brief     Initializes the communication interface used by this transport layer.
97
** \param     device Serial communication device name. For example "COM4".
98
** \param     baudrate Communication speed in bits/sec.
99
** \return    SB_TRUE if successful, SB_FALSE otherwise.
100
**
101
****************************************************************************************/
102
sb_uint8 XcpTransportInit(sb_char *device, sb_uint32 baudrate, sb_uint8 comIsUart)
103
{
104
  // registers for UART connection
105
  struct termios options;
106

    
107
/*
108
  // socket structs for Bluetooth connection
109
  const struct timeval sock_timeout = {.tv_sec=0, .tv_usec=100000};
110
  struct sockaddr_rc addr = { 0 };
111
*/
112

    
113
  // additional initializations
114
  int status;
115

    
116

    
117
  // save input
118
  tcpDevice = device;
119
  tcpBaudrate = baudrate;
120
  tcpComIsUart = comIsUart;
121

    
122

    
123

    
124
  // check, if maybe existing serial port has been closed first
125
  if (hUart != UART_INVALID_HANDLE) {
126
    if (errorType > 0 && errorType != EAGAIN) {
127
       //printf("Close active connection.\n");
128
       XcpTransportClose();
129
    } else if (errorType == EAGAIN || errorType == 0) {
130
       //printf("Just try sending message again!\n");
131

    
132
       return SB_TRUE;
133
    }
134
  }
135
  errorType = 0;
136

    
137
/*
138
  // try to connect to bluetooth device
139
  if (comIsUart == SB_FALSE) {
140
    printf("Connection over Bluetooth\n");
141
    // allocate a socket
142
    hUart = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
143

144
    // set the connection parameters (who to connect to)
145
    addr.rc_family = AF_BLUETOOTH;
146
    addr.rc_channel = bluetooth_channel;
147
    str2ba(device, &addr.rc_bdaddr); // with "-lbluetooth"
148

149
    // connect to server
150
    status = connect(hUart, (struct sockaddr *)&addr, sizeof(addr));
151
    if (status < 0) {
152
      printf("could not connect to bluetooth device (status = %i)\n", errno);
153
      //XcpTransportClose();
154
      return SB_FALSE;
155
    }
156

157
    setsockopt(hUart, SOL_SOCKET, SO_RCVTIMEO, (char*)&sock_timeout, sizeof(sock_timeout));
158

159
    printf("Bluetooth connection built\n");
160
    return SB_TRUE;
161
  }
162

163
  printf("Connection over UART\n");
164
*/
165

    
166
  /* open the port */
167
  hUart = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
168
  /* verify the result */
169
  if (hUart == UART_INVALID_HANDLE)
170
  {
171
    return SB_FALSE;
172
  }
173
  /* configure the device to block during read operations */
174
  if (fcntl(hUart, F_SETFL, 0) == -1)
175
  {
176
    XcpTransportClose();
177
    return SB_FALSE;
178
  }
179
  /* get the current options for the port */
180
  if (tcgetattr(hUart, &options) == -1)
181
  {
182
    XcpTransportClose();
183
    return SB_FALSE;
184
  }
185

    
186
  /* reset the settings */
187
  cfmakeraw(&options);
188
  options.c_cflag &= ~(CSIZE | CRTSCTS);
189
  options.c_iflag &= ~(IXON | IXOFF | IXANY | IGNPAR);
190
  options.c_lflag &= ~(ECHOK | ECHOCTL | ECHOKE);
191
  options.c_oflag &= ~(OPOST | ONLCR);
192

    
193
  /* configure the baudrate */
194
  if (cfsetispeed(&options, XcpTransportGetBaudrateMask(baudrate)) == -1)
195
  {
196
    XcpTransportClose();
197
    return SB_FALSE;
198
  }
199
  if (cfsetospeed(&options, XcpTransportGetBaudrateMask(baudrate)) == -1)
200
  {
201
    XcpTransportClose();
202
    return SB_FALSE;
203
  }
204
  /* enable the receiver and set local mode */
205
  options.c_cflag |= (CLOCAL | CREAD);
206
  /* configure 8-n-1 */
207
  options.c_cflag &= ~PARENB;
208
  options.c_cflag &= ~CSTOPB;
209
  options.c_cflag &= ~CSIZE;
210
  options.c_cflag |= CS8;
211
  /* disable hardware flow control */
212
  options.c_cflag &= ~CRTSCTS;
213
  /* configure raw input */
214
  options.c_lflag &= ~(ICANON | ISIG);
215
  /* configure raw output */
216
  options.c_oflag &= ~OPOST;
217
  /* configure timeouts */
218
  options.c_cc[VMIN]  = 0;
219
  options.c_cc[VTIME] = UART_RX_TIMEOUT_MIN_MS/100; /* 1/10th of a second */
220

    
221
  /* pull down reset pin */
222
  if (ioctl(hUart, TIOCMGET, &status) == -1) {
223
    perror("TIOCMGET");
224
    return SB_FALSE;
225
  }
226
  status |= TIOCM_DTR;
227
  status &= ~TIOCM_RTS;
228
  if (ioctl(hUart, TIOCMSET, &status) == -1) {
229
    perror("TIOCMSET");
230
    return SB_FALSE;
231
  }
232

    
233
  /* set the new options for the port */
234
  if (tcsetattr(hUart, TCSAFLUSH, &options) == -1)
235
  {
236
    XcpTransportClose();
237
    return SB_FALSE;
238
  }
239

    
240
  /* success */
241
  return SB_TRUE;
242
} /*** end of XcpTransportInit ***/
243

    
244

    
245
/************************************************************************************//**
246
** \brief     Transmits an XCP packet on the transport layer and attemps to receive the
247
**            response within the given timeout. The data in the response packet is
248
**            stored in an internal data buffer that can be obtained through function
249
**            XcpTransportReadResponsePacket().
250
** \return    SB_TRUE is the response packet was successfully received and stored,
251
**            SB_FALSE otherwise.
252
**
253
****************************************************************************************/
254
sb_uint8 XcpTransportSendPacket(sb_uint8 *data, sb_uint8 len, sb_uint16 timeOutMs)
255
{
256
  sb_uint16 cnt;
257
  static sb_uint8 xcpUartBuffer[XCP_MASTER_UART_MAX_DATA]; /* static to lower stack load */
258
  sb_uint16 xcpUartLen;
259
  sb_int32 bytesSent;
260
  sb_int32 bytesToRead;
261
  sb_int32 bytesRead;
262
  sb_uint8 *uartReadDataPtr;
263
  sb_uint32 timeoutTime;
264
  sb_uint32 nowTime;
265
  ssize_t result;
266

    
267
  struct timeval start, send, end;
268

    
269
  gettimeofday(&start, NULL);
270

    
271
  /* ------------------------ XCP packet transmission -------------------------------- */
272
  /* prepare the XCP packet for transmission on UART. this is basically the same as the
273
   * xcp packet data but just the length of the packet is added to the first byte.
274
   */
275
  xcpUartLen = len+1;
276
  xcpUartBuffer[0] = len;
277
  for (cnt=0; cnt<len; cnt++)
278
  {
279
    xcpUartBuffer[cnt+1] = data[cnt];
280
  }
281

    
282
  bytesSent = -1;
283

    
284
  while (bytesSent != xcpUartLen) {
285

    
286
    bytesSent = write(hUart, xcpUartBuffer, xcpUartLen);
287

    
288
    if (bytesSent != xcpUartLen)
289
    {
290
      errorType = errno;
291
/*      if (errorType == EAGAIN) {
292
        printf("<< ERROR EAGAIN >>\n");
293
      } else {
294
        printf("<< ERROR %i >>\n", errorType);
295
      }*/
296
//      while(XcpTransportInit(tcpDevice, tcpBaudrate, tcpComIsUart) == SB_FALSE);
297
//      return XcpTransportSendPacket(data, len, timeOutMs);
298
      return SB_FALSE;
299
    }
300
  }
301

    
302
  /* ------------------------ XCP packet reception ----------------------------------- */
303
  /* determine timeout time */
304
  timeoutTime = TimeUtilGetSystemTimeMs() + timeOutMs + UART_RX_TIMEOUT_MIN_MS;
305

    
306
  /* read the first byte, which contains the length of the xcp packet that follows */
307
  bytesToRead = 1;
308
  uartReadDataPtr = &responsePacket.len;
309
  while(bytesToRead > 0)
310
  {
311
//    printf("bytesToRead: %i\n", bytesToRead);
312
    result = read(hUart, uartReadDataPtr, bytesToRead);
313
    if (result == -1) {
314
      errorType = errno;
315
/*      if (errno == EAGAIN) {
316
        printf("<< ERROR EAGAIN >>\n");
317
      } else {
318
        printf("<< ERROR %i >>\n", errno);
319
      }
320
*///      while(XcpTransportInit(tcpDevice, tcpBaudrate, tcpComIsUart) == SB_FALSE);
321
//      return XcpTransportSendPacket(data, len, timeOutMs);
322
//        return SB_FALSE;
323
    }
324
    if (result != -1)
325
    {
326
      bytesRead = result;
327
      /* update the bytes that were already read */
328
      uartReadDataPtr += bytesRead;
329
      bytesToRead -= bytesRead;
330
    }
331
    /* check for timeout if not yet done */
332
    if ( (bytesToRead > 0) && (TimeUtilGetSystemTimeMs() >= timeoutTime) )
333
    {
334
//      printf("\nTIMEOUT of first byte received - ");
335
      /* timeout occurred */
336
      return SB_FALSE;
337
    }
338
  }
339
  gettimeofday(&send, NULL);
340

    
341
//  printf("\nfirst byte received, checking rest\n");
342

    
343
  /* read the rest of the packet */
344
  bytesToRead = responsePacket.len;
345
  uartReadDataPtr = &responsePacket.data[0];
346
  while(bytesToRead > 0)
347
  {
348
    result = read(hUart, uartReadDataPtr, bytesToRead);
349
    if (result != -1)
350
    {
351
      bytesRead = result;
352
      /* update the bytes that were already read */
353
      uartReadDataPtr += bytesRead;
354
      bytesToRead -= bytesRead;
355
    }
356
    /* check for timeout if not yet done */
357
    if ( (bytesToRead > 0) && (TimeUtilGetSystemTimeMs() >= timeoutTime) )
358
    {
359
//      printf("\nTIMEOUT of other bytes received - ");
360
      /* timeout occurred */
361
      return SB_FALSE;
362
    }
363
  }
364
//  printf("\nall received!\n");
365
  gettimeofday(&end, NULL);
366
//  printf("Sending: %luus, Receiving: %luus, all: %luus (bytes sent: %u)\n", send.tv_usec-start.tv_usec, end.tv_usec-send.tv_usec, end.tv_usec-start.tv_usec, bytesSent);
367
  /* still here so the complete packet was received */
368
  return SB_TRUE;
369
} /*** end of XcpMasterTpSendPacket ***/
370

    
371

    
372
/************************************************************************************//**
373
** \brief     Reads the data from the response packet. Make sure to not call this
374
**            function while XcpTransportSendPacket() is active, because the data won't be
375
**            valid then.
376
** \return    Pointer to the response packet data.
377
**
378
****************************************************************************************/
379
tXcpTransportResponsePacket *XcpTransportReadResponsePacket(void)
380
{
381
  return &responsePacket;
382
} /*** end of XcpTransportReadResponsePacket ***/
383

    
384

    
385
/************************************************************************************//**
386
** \brief     Closes the communication channel.
387
** \return    none.
388
**
389
****************************************************************************************/
390
void XcpTransportClose(void)
391
{
392
  /* close the COM port handle if valid */
393
  if (hUart != UART_INVALID_HANDLE)
394
  {
395
    close(hUart);
396
  }
397

    
398
  /* set handles to invalid */
399
  hUart = UART_INVALID_HANDLE;
400
} /*** end of XcpTransportClose ***/
401

    
402

    
403
/************************************************************************************//**
404
** \brief     Converts the baudrate value to a bitmask value used by termios. Currently
405
**            supports the most commonly used baudrates.
406
** \return    none.
407
**
408
****************************************************************************************/
409
static speed_t XcpTransportGetBaudrateMask(sb_uint32 baudrate)
410
{
411
  speed_t result;
412

    
413
  switch (baudrate)
414
  {
415
    case 115200:
416
      result = B115200;
417
      break;
418
    case 57600:
419
      result = B57600;
420
      break;
421
    case 38400:
422
      result = B38400;
423
      break;
424
    case 19200:
425
      result = B19200;
426
      break;
427
    case 9600:
428
    default:
429
      result = B9600;
430
      break;
431
  }
432
  return result;
433
} /*** end of XcpTransportGetBaudrateMask ***/
434

    
435

    
436
/*********************************** end of xcptransport.c *****************************/