| 1 | #ifndef _DIAG_H_ |
| 2 | #define _DIAG_H_ |
| 3 | |
| 4 | /* |
| 5 | * freediag - Vehicle Diagnostic Utility |
| 6 | * |
| 7 | * |
| 8 | * Copyright (C) 2001 Richard Almeida & Ibex Ltd ([email protected]) |
| 9 | * 2014-2015 fenugrec |
| 10 | * |
| 11 | * This program is free software; you can redistribute it and/or modify |
| 12 | * it under the terms of the GNU General Public License as published by |
| 13 | * the Free Software Foundation; either version 2 of the License, or |
| 14 | * (at your option) any later version. |
| 15 | * |
| 16 | * This program is distributed in the hope that it will be useful, |
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 19 | * GNU General Public License for more details. |
| 20 | * |
| 21 | * You should have received a copy of the GNU General Public License |
| 22 | * along with this program; if not, write to the Free Software |
| 23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| 24 | * |
| 25 | ************************************************************************* |
| 26 | * |
| 27 | * Library user header file |
| 28 | */ |
| 29 | |
| 30 | #if defined(__cplusplus) |
| 31 | extern "C" { |
| 32 | #endif |
| 33 | |
| 34 | #include "cconf.h" |
| 35 | |
| 36 | #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) |
| 37 | #ifndef _WIN32_WINNT |
| 38 | #define _WIN32_WINNT 0x0500 //use > winXP features... |
| 39 | #endif |
| 40 | #include <time.h> |
| 41 | #include <basetsd.h> |
| 42 | #include <windows.h> |
| 43 | #else |
| 44 | #include <sys/types.h> |
| 45 | #endif |
| 46 | |
| 47 | #include <stdbool.h> |
| 48 | #include <stdint.h> /* For uint8_t, etc. This is a C99 header */ |
| 49 | |
| 50 | #if defined(_MSC_VER) |
| 51 | //silence warnings about non-portable "_s" function replacements. |
| 52 | //this must be set before including <stdio.h>. |
| 53 | #define _CRT_SECURE_NO_WARNINGS |
| 54 | #pragma warning(disable:4996) |
| 55 | #endif /* _MSC_VER Visual Studio */ |
| 56 | #include <stdio.h> /* For FILE */ |
| 57 | |
| 58 | #include "diag_os.h" //for mutexes... |
| 59 | |
| 60 | // Nice to have anywhere... |
| 61 | #define MIN(_a_, _b_) (((_a_) < (_b_) ? (_a_) : (_b_))) |
| 62 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) |
| 63 | #define FLFMT "%s:%d: " //for debug messages |
| 64 | |
| 65 | |
| 66 | #ifdef HAVE_STRCASECMP |
| 67 | #include <strings.h> |
| 68 | #else |
| 69 | #ifdef _WIN32 |
| 70 | //strcasecmp is POSIX, but kernel32 provides lstrcmpi which should be equivalent. |
| 71 | #define strcasecmp(a,b) lstrcmpi((LPCTSTR) a, (LPCTSTR) b) |
| 72 | #else |
| 73 | #error Your system provides no strcasecmp ! This is a problem ! |
| 74 | #endif //WIN32 |
| 75 | #endif //HAVE_STRCASECMP |
| 76 | |
| 77 | |
| 78 | #define DB_FILE "./freediag_carsim_all.db" //default simfile for CARSIM interface |
| 79 | #define DIAG_NAMELEN 256 |
| 80 | |
| 81 | |
| 82 | /****** compiler-specific tweaks ******/ |
| 83 | #ifdef __GNUC__ |
| 84 | #define UNUSED(X) X __attribute__((unused)) //magic ! |
| 85 | #else |
| 86 | #define UNUSED(X) X //how can we suppress "unused parameter" warnings on other compilers? |
| 87 | #endif // __GNUC__ |
| 88 | |
| 89 | //hacks for MS Visual studio / visual C |
| 90 | #if defined(_MSC_VER) |
| 91 | typedef SSIZE_T ssize_t; //XXX ssize_t is currently only needed because of diag_tty_unix.c:diag_tty_{read,write}. |
| 92 | //TODO : rework read/write types to use a combination of size_t and int ? |
| 93 | #if _MSC_VER < 1910 /* anything older than Visual Studio 2017 */ |
| 94 | #define snprintf _snprintf //danger : _snprintf doesn't guarantee zero-termination !? |
| 95 | //as of Visual Studio 2015 the snprintf function is c99 compatible. |
| 96 | //https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/snprintf-snprintf-snprintf-l-snwprintf-snwprintf-l?view=msvc-160 |
| 97 | #pragma message("Warning: MSVC _sprintf() may be dangerous ! Please ask your compiler vendor to supply a C99-compliant snprintf()...") |
| 98 | //CURFILE will be defined by CMake on a per-file basis ! |
| 99 | #pragma message("Warning: MSVC may not work with the CURFILE macro. See diag.h") |
| 100 | // apparently some (all ?) MSVC compilers don't support per-file defines, so CURFILE would be the |
| 101 | // same for all source files. |
| 102 | // The disadvantage of __FILE__ is that it often (always ?) holds the absolute path of the file, |
| 103 | // not just the filename. For our debugging messages we only care about the filename, hence CURFILE. |
| 104 | #define FL __FILE__, __LINE__ |
| 105 | #else |
| 106 | // Using Visual Studio 2017 and higher the CURFILE macro will work. |
| 107 | #define FL CURFILE, __LINE__ |
| 108 | #endif /* _MSC_VER < 1910 Visual Studio 2017 */ |
| 109 | #else |
| 110 | #define FL CURFILE, __LINE__ |
| 111 | #endif /* _MSC_VER Visual Studio */ |
| 112 | /****** ******/ |
| 113 | |
| 114 | /* |
| 115 | * Many receive buffers are set to this, which is voluntarily larger than |
| 116 | * any possible valid message to/from an ECU. |
| 117 | */ |
| 118 | #define MAXRBUF 1024 |
| 119 | |
| 120 | #define DIAG_MAX_MSGLEN 4200 /** limit diag_allocmsg() message size. */ |
| 121 | |
| 122 | typedef uint8_t target_type, source_type, databyte_type, command_type; |
| 123 | typedef uint16_t flag_type; //this is used for L2 type flags (see diag_l2.h) |
| 124 | //only used for diag_l2_startcomms() arg |
| 125 | |
| 126 | /* |
| 127 | * IOCTLs |
| 128 | * |
| 129 | * The IOCTL can be done to any layer, and it is passed downward with |
| 130 | * each layer filling in info as needed (there are currently no clashes) |
| 131 | * |
| 132 | * Values for "cmd" parameter to diag_l[12]_ioctl() |
| 133 | * XXX Are their numeric values chosen on purpose ? i.e. why "2023" etc. |
| 134 | */ |
| 135 | |
| 136 | #define DIAG_IOCTL_GET_L1_TYPE 0x2010 /* Get L1 Type, data is ptr to int */ |
| 137 | #define DIAG_IOCTL_GET_L1_FLAGS 0x2011 /* Get L1 Flags, data is ptr to int */ |
| 138 | #define DIAG_IOCTL_GET_L2_FLAGS 0x2021 /* Get the L2 flags (see fmt stuff )*/ |
| 139 | #define DIAG_IOCTL_GET_L2_DATA 0x2023 /* Get the L2 Keybytes etc into |
| 140 | * diag_l2_data passed to us |
| 141 | */ |
| 142 | #define DIAG_IOCTL_SETSPEED 0x2101 /* Set speed, bits etc. data = (const struct diag_serial_settings *); ret 0 if ok |
| 143 | * Ignored if DIAG_L1_AUTOSPEED or DIAG_L1_NOTTY is set */ |
| 144 | #define DIAG_IOCTL_INITBUS 0x2201 /* Initialise the ecu bus, data = (struct diag_l1_initbus_args *) |
| 145 | * |
| 146 | * Caller must have waited the appropriate time before calling this, since any |
| 147 | * bus-idle requirements are specified at the L2 level. |
| 148 | * Must return as soon as possible, |
| 149 | * and restore original port settings (speed, etc). |
| 150 | * See diag_l1.h for initbus args |
| 151 | * return 0 if ok |
| 152 | */ |
| 153 | #define DIAG_IOCTL_IFLUSH 0x2202 /* flush input buffers. No data. Ignored if DIAG_L1_NOTTY is set. |
| 154 | * Ret 0 if ok / not applicable (non fatal error) */ |
| 155 | /** Set wake-up (keepalive) message. |
| 156 | * Only applicable if DIAG_L1_DOESKEEPALIVE is set |
| 157 | * |
| 158 | * data = (struct diag_msg *). |
| 159 | * The (struct diag_msg)->data member must be a raw message (including headers) |
| 160 | * |
| 161 | * data can be freed by caller after the ioctl (L0 will make a copy of the message data as required) |
| 162 | */ |
| 163 | #define DIAG_IOCTL_SETWM 0x2203 |
| 164 | |
| 165 | /****** debug control ******/ |
| 166 | // flag containers : diag_l0_debug, diag_l1_debug diag_l2_debug, diag_l3_debug, diag_cli_debug |
| 167 | |
| 168 | #define DIAG_DEBUG_OPEN 0x01 /* Open events */ |
| 169 | #define DIAG_DEBUG_CLOSE 0x02 /* Close events */ |
| 170 | #define DIAG_DEBUG_READ 0x04 /* Read events */ |
| 171 | #define DIAG_DEBUG_WRITE 0x08 /* Write events */ |
| 172 | #define DIAG_DEBUG_IOCTL 0x10 /* Ioctl stuff (setspeed etc) */ |
| 173 | #define DIAG_DEBUG_PROTO 0x20 /* Other protocol stuff */ |
| 174 | #define DIAG_DEBUG_INIT 0x40 /* Initialisation stuff */ |
| 175 | #define DIAG_DEBUG_DATA 0x80 /* Dump data depending on other flags */ |
| 176 | #define DIAG_DEBUG_TIMER 0x100 /* Timer stuff */ |
| 177 | |
| 178 | |
| 179 | // these are for identifying the debug message prefix to be printed |
| 180 | enum debug_prefix { |
| 181 | DIAG_DEBUGPF_NONE, |
| 182 | DIAG_DEBUGPF_OPEN, |
| 183 | DIAG_DEBUGPF_CLOSE, |
| 184 | DIAG_DEBUGPF_READ, |
| 185 | DIAG_DEBUGPF_WRITE, |
| 186 | DIAG_DEBUGPF_IOCTL, |
| 187 | DIAG_DEBUGPF_PROTO, |
| 188 | DIAG_DEBUGPF_INIT, |
| 189 | DIAG_DEBUGPF_DATA, |
| 190 | DIAG_DEBUGPF_TIMER |
| 191 | }; |
| 192 | |
| 193 | /** debug message prefixes : dbg_prefixes[DIAG_DEBUGPF_XYZ] is a const char* |
| 194 | */ |
| 195 | extern const char *dbg_prefixes[]; |
| 196 | |
| 197 | |
| 198 | /**** debug message helpers. |
| 199 | * |
| 200 | * These macros will allow changing the backend and destination (stderr, file, etc) |
| 201 | * |
| 202 | */ |
| 203 | |
| 204 | #define DIAG_DBGLEVEL_V 0 |
| 205 | |
| 206 | /** for diag.h internal use only */ |
| 207 | #define DIAG_DBG_BACKEND(...) fprintf(stderr, __VA_ARGS__) |
| 208 | |
| 209 | |
| 210 | /** print general debug message |
| 211 | * |
| 212 | */ |
| 213 | #define DIAG_DBGGEN(level, ...) DIAG_DBG_BACKEND(__VA_ARGS__); |
| 214 | |
| 215 | |
| 216 | /** simple debug message formatter |
| 217 | * |
| 218 | * flagvar is the i.e. "diag_l1_debug" that is checked against mask. |
| 219 | * mask: see DIAG_DEBUG_* defs above |
| 220 | * level: not used yet |
| 221 | * |
| 222 | * Must be used for all non-essential messages. Does not add "\n" |
| 223 | * |
| 224 | */ |
| 225 | #define DIAG_DBGM(flagvar, mask, level, ...) do { \ |
| 226 | if (((flagvar) & (mask)) == (mask)) { \ |
| 227 | DIAG_DBG_BACKEND(__VA_ARGS__); \ |
| 228 | }} while (0) |
| 229 | |
| 230 | /** debug message formatter with data |
| 231 | * |
| 232 | * flagvar is the i.e. "diag_l1_debug" that is checked against mask. |
| 233 | * mask: see DIAG_DEBUG_* defs above. No need to specify DIAG_DEBUG_DATA |
| 234 | * level: not used yet |
| 235 | * |
| 236 | * varargs: always printed. Automatically adds trailing "\n" |
| 237 | * |
| 238 | * Must be used for all non-essential messages. |
| 239 | * |
| 240 | */ |
| 241 | #define DIAG_DBGMDATA(flagvar, mask, level, data, datalen, ...) do { \ |
| 242 | if (((flagvar) & (mask)) == (mask)) { \ |
| 243 | DIAG_DBG_BACKEND(__VA_ARGS__); \ |
| 244 | if ((flagvar) & DIAG_DEBUG_DATA) { \ |
| 245 | diag_data_dump(stderr, data, datalen); \ |
| 246 | } \ |
| 247 | fprintf(stderr, "\n"); \ |
| 248 | }} while (0) |
| 249 | |
| 250 | |
| 251 | /* |
| 252 | * Message handling. |
| 253 | * |
| 254 | * These are messages passed to or from the layer 2 and layer 3 code |
| 255 | * which cause data to be transmitted to layer 1 |
| 256 | * |
| 257 | * The receiver of the message *must* copy the data if it wants it !!! |
| 258 | * The flags are arranged such as zeroing out the whole structure sets "safe" defaults. |
| 259 | * There's probably no application for 0-length messages, but currently the various functions |
| 260 | * don't complain when allocating/duplicating empty data. |
| 261 | */ |
| 262 | struct diag_msg { |
| 263 | uint8_t fmt; /* Message format (doesn't absolutely need to be uint8_t) : */ |
| 264 | #define DIAG_FMT_ISO_FUNCADDR 0x01 /* ISO Functional addressing (default : phys) */ |
| 265 | #define DIAG_FMT_FRAMED 0x02 /* Rcvd data is framed, ie not raw. XXX DEPRECATED ! L0..L2 all do this.*/ |
| 266 | // #define DIAG_FMT_DATAONLY 0x04 /* Rcvd data had L2/L3 headers removed XXX ALWAYS ! */ |
| 267 | #define DIAG_FMT_CKSUMMED 0x08 /* Someone (L1/L2) checked the checksum */ |
| 268 | #define DIAG_FMT_BADCS 0x10 // message has bad checksum |
| 269 | |
| 270 | uint8_t type; /* Type from received frame */ |
| 271 | uint8_t dest; /* Destination from received frame */ |
| 272 | uint8_t src; /* Source from received frame */ |
| 273 | |
| 274 | unsigned len; /* calculated data length */ |
| 275 | uint8_t *data; /* The data; can be dynamically alloc'ed */ |
| 276 | |
| 277 | unsigned long rxtime; /* Processing timestamp, in ms given by diag_os_getms() */ |
| 278 | struct diag_msg *next; /* For linked lists of messages */ |
| 279 | |
| 280 | uint8_t *idata; /* For free() of data later: this is a "backup" |
| 281 | * of the initial *data pointer.*/ |
| 282 | uint8_t iflags; /* Internal flags */ |
| 283 | #define DIAG_MSG_IFLAG_MALLOC 1 /* We malloced; we Free -- this is set when the msg |
| 284 | * was created by diag_allocmsg()*/ |
| 285 | }; |
| 286 | |
| 287 | /** Allocate a new diag_msg |
| 288 | * |
| 289 | * Also allocates diag_msg-\>data if datalen\>0. |
| 290 | * @param datalen: if \>0, size of data buffer to allocate. Max DIAG_MAX_MSGLEN. |
| 291 | * @return new struct diag_msg, must be freed with diag_freemsg(). |
| 292 | */ |
| 293 | struct diag_msg *diag_allocmsg(size_t datalen); |
| 294 | /** Duplicate a diag_msg, including all chained messages and their contents. |
| 295 | * @return new struct diag_msg, must be freed with diag_freemsg(). |
| 296 | */ |
| 297 | struct diag_msg *diag_dupmsg(struct diag_msg *); |
| 298 | |
| 299 | /** Duplicate a single diag_msg, without following the linked-list chain. |
| 300 | * @return new struct diag_msg, must be freed with diag_freemsg(). |
| 301 | */ |
| 302 | struct diag_msg *diag_dupsinglemsg(struct diag_msg *); |
| 303 | |
| 304 | /** Free a diag_msg |
| 305 | * Safe to call with NULL arg |
| 306 | */ |
| 307 | void diag_freemsg(struct diag_msg *); |
| 308 | |
| 309 | /** Calculate 8bit checksum |
| 310 | * @param len: number of bytes in *data |
| 311 | * @return 8-bit sum of all bytes |
| 312 | */ |
| 313 | uint8_t diag_cks1(const uint8_t *data, unsigned int len); |
| 314 | |
| 315 | |
| 316 | void diag_printmsg_header(FILE *fp, struct diag_msg *msg, bool timestamp, int msgnum); |
| 317 | void diag_printmsg(FILE *fp, struct diag_msg *msg, bool timestamp); |
| 318 | |
| 319 | /* |
| 320 | * General functions |
| 321 | */ |
| 322 | //diag_init : ret 0 if ok; |
| 323 | int diag_init(void); |
| 324 | //diag_end : must be called before exiting. Ret 0 if ok |
| 325 | int diag_end(void); |
| 326 | |
| 327 | /** Print bytes in hex format |
| 328 | * @param out: output stream (file / stderr / etc.) |
| 329 | * @param len: # of bytes to print |
| 330 | * |
| 331 | * Prints bytes with "0x%02X" formatter, e.g. "0x55 0xAA 0x03 " |
| 332 | */ |
| 333 | void diag_data_dump(FILE *out, const void *data, size_t len); |
| 334 | |
| 335 | //smartcat : only verifies if s1 is not too large ! |
| 336 | void smartcat(char *p1, const size_t s1, const char *p2 ); |
| 337 | |
| 338 | /* |
| 339 | * Error functions. |
| 340 | * diag_p_* aren't intended to be called directly. |
| 341 | * Use "diag_pseterr" (returns a NULL pointer) or |
| 342 | * "diag_iseterr" (returns the passed in error code), |
| 343 | * which will save where the error took place and optionally log it. |
| 344 | */ |
| 345 | |
| 346 | void *diag_p_pseterr(const char *name, const int line, const int code); |
| 347 | int diag_p_iseterr(const char *name, const int line, const int code); |
| 348 | void *diag_p_pfwderr(const char *name, const int line, const int code); |
| 349 | int diag_p_ifwderr(const char *name, const int line, const int code); |
| 350 | |
| 351 | /** return NULL, set and print error. */ |
| 352 | #define diag_pseterr(C) diag_p_pseterr(CURFILE, __LINE__, (C)) |
| 353 | /** return (C), set and print error. */ |
| 354 | #define diag_iseterr(C) diag_p_iseterr(CURFILE, __LINE__, (C)) |
| 355 | |
| 356 | /** return NULL, print error as a debug msg */ |
| 357 | #define diag_pfwderr(C) diag_p_pfwderr(CURFILE, __LINE__, (C)) |
| 358 | /** return (C), print error as a debug msg */ |
| 359 | #define diag_ifwderr(C) diag_p_ifwderr(CURFILE, __LINE__, (C)) |
| 360 | |
| 361 | |
| 362 | /** Return the last error and clears it. |
| 363 | */ |
| 364 | int diag_geterr(void); |
| 365 | |
| 366 | /** Get textual description of error |
| 367 | * |
| 368 | * Note, it returns a pointer to a statically allocated buffer |
| 369 | * common to all threads and that must not be free'd. |
| 370 | */ |
| 371 | const char *diag_errlookup(const int code); |
| 372 | |
| 373 | /* |
| 374 | * "calloc" and "malloc" that log errors when they fail. |
| 375 | * As with the seterr functions, only "diag_calloc" and "diag_malloc" |
| 376 | * are intended to be called directly. |
| 377 | * |
| 378 | */ |
| 379 | |
| 380 | // Do not call directly. |
| 381 | int diag_fl_alloc(const char *fName, const int line, |
| 382 | void **pp, size_t n, size_t s, bool allocIsCalloc); |
| 383 | |
| 384 | /** calloc() with logging (clears data) |
| 385 | * @param P: *ptr |
| 386 | * @param N: number of (sizeof) elems to allocate |
| 387 | * @return 0 if OK |
| 388 | * @note there is no size argument - it gets it directly |
| 389 | * using sizeof. This makes it a little unusual, but reduces potential errors. |
| 390 | */ |
| 391 | #define diag_calloc(P, N) diag_fl_alloc(CURFILE, __LINE__, \ |
| 392 | ((void **)(P)), (N), sizeof(**(P)), true) |
| 393 | |
| 394 | /** malloc() with logging. |
| 395 | * @return 0 if OK |
| 396 | * Same as diag_calloc, but without clearing. |
| 397 | */ |
| 398 | #define diag_malloc(P, N) diag_fl_alloc(CURFILE, __LINE__, \ |
| 399 | ((void **)(P)), (N), sizeof(**(P)), false) |
| 400 | |
| 401 | /** Add a string to array-of-strings (argv style) |
| 402 | * @param elems: number of elements already in table |
| 403 | * @return new table ptr, NULL if failed |
| 404 | */ |
| 405 | char **strlist_add(char **list, const char *news, int elems); |
| 406 | |
| 407 | /** Free argv-style string list |
| 408 | * @param elems: number of strings in list |
| 409 | */ |
| 410 | void strlist_free(char **slist, int elems); |
| 411 | |
| 412 | // Atomics |
| 413 | |
| 414 | // Atomically accessed types |
| 415 | typedef struct { |
| 416 | diag_mtx mtx; |
| 417 | bool v; |
| 418 | } diag_atomic_bool; |
| 419 | typedef struct { |
| 420 | diag_mtx mtx; |
| 421 | int v; |
| 422 | } diag_atomic_int; |
| 423 | |
| 424 | #define diag_atomic_init(V) diag_os_initstaticmtx(&((V)->mtx)) |
| 425 | #define diag_atomic_del(V) diag_os_delmtx(&((V)->mtx)) |
| 426 | |
| 427 | void diag_atomic_store_bool(diag_atomic_bool *a, bool d); |
| 428 | void diag_atomic_store_int(diag_atomic_int *a, int d); |
| 429 | bool diag_atomic_load_bool(diag_atomic_bool *a); |
| 430 | int diag_atomic_load_int(diag_atomic_int *a); |
| 431 | |
| 432 | /** Check if periodic timers have finished |
| 433 | * |
| 434 | * Returns true if the periodic timer is no longer necessary, ie. if the diag_end has been |
| 435 | * run. Returns false otherwise. |
| 436 | */ |
| 437 | bool periodic_done(void); |
| 438 | |
| 439 | #if defined(__cplusplus) |
| 440 | } |
| 441 | #endif |
| 442 | |
| 443 | #endif /* _DIAG_H_ */ |
| 444 | |