├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── ccl_test.dbc ├── datenbasis.c ├── datenbasis.h ├── lib.c ├── lib.h ├── main.c ├── processFrame.c ├── processFrame.h └── uthash.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libcan-encode-decode"] 2 | path = libcan-encode-decode 3 | url = https://github.com/reinzor/libcan-encode-decode.git 4 | branch = heads/master 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Eduard Bröcker 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 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SocketCandecodeSignals 2 | filter to decode signals in combination with candump (socketcan tools) 3 | 4 | # clone # 5 | ``` 6 | git clone https://github.com/ebroecker/SocketCandecodeSignals 7 | git submodule update --init 8 | ``` 9 | or 10 | ``` 11 | git clone --recursive https://github.com/ebroecker/SocketCandecodeSignals 12 | ``` 13 | 14 | # Compile # 15 | ```gcc -g -o socketcanDecodeSignal main.c datenbasis.c processFrame.c lib.c``` 16 | 17 | ## Usage ## 18 | ``` 19 | candump -L canBus | ./socketcanDecodeSignal dbc-file frameName[.signalName] [secondFrame[.someSignal] ...] 20 | ``` 21 | ***Example*** 22 | ``` 23 | candump -L vcan0 | ./socketcanDecodeSignal ccl_test.dbc testFrame1.sig0 testFrame2 24 | ``` 25 | 26 | # Test # 27 | ***prepare virtual can:*** 28 | ``` 29 | sudo modprobe vcan 30 | sudo ip link add type vcan 31 | sudo ifconfig vcan0 up 32 | ``` 33 | 34 | ***dump vcan0 with signal decoding:*** 35 | ``` 36 | candump -L vcan0 | ./socketcanDecodeSignal ccl_test.dbc testFrame1 testFrame2 37 | ``` 38 | 39 | ***send some can frames (other terminal)*** 40 | ``` 41 | cansend vcan0 001#8d00100100820100 42 | cansend vcan0 002#0C00057003CD1F83 43 | ``` 44 | 45 | ***will result:*** 46 | ``` 47 | Trying to find: Frame: testFrame1 48 | -- testFrame1 (0x001) 49 | Trying to find: Frame: testFrame2 50 | -- testFrame2 (0x002) 51 | (1456687759.303127) vcan0 sig0: 0x01 01 52 | (1456687759.303127) vcan0 sig1: 0x23 35 53 | (1456687759.303127) vcan0 sig2: 0x00 00 54 | (1456687759.303127) vcan0 sig3: 0x800 2048 55 | (1456687759.303127) vcan0 sig4: 0x100 256 56 | (1456687759.303127) vcan0 sig5: 0x01 01 57 | (1456687759.303127) vcan0 sig6: 0x00 00 58 | (1456687759.303127) vcan0 sig7: 0x208 520 59 | (1456687759.303127) vcan0 sig8: 0x00 00 60 | (1456687759.303127) vcan0 sig9: 0x00 00 61 | (1456687759.303127) vcan0 sig10: 0x00 00 62 | (1456687763.319899) vcan0 secSig1: 0x00 00 63 | (1456687763.319899) vcan0 secSig2: 0x00 00 64 | (1456687763.319899) vcan0 secSig3: 0x00 00 65 | (1456687763.319899) vcan0 secSig4: 0x02 02 66 | (1456687763.319899) vcan0 secSig5: 0x00 00 67 | (1456687763.319899) vcan0 secSig6: 0x00 00 68 | (1456687763.319899) vcan0 secSig7: 0x00 00 69 | (1456687763.319899) vcan0 secSig8: 0x03 03 70 | (1456687763.319899) vcan0 secSig9: 0x01 01 71 | (1456687763.319899) vcan0 secSig10: 0x500 1280 72 | (1456687763.319899) vcan0 secSig11: 0xffffffffffffff70 -144 73 | (1456687763.319899) vcan0 secSig12: 0x0c 12 74 | ``` 75 | 76 | 77 | ***Test without virtual can:*** 78 | ``` 79 | echo "(0.0) vcan0 001#8d00100100820100" | ./socketcanDecodeSignal ccl_test.dbc testFrame1 80 | ``` 81 | 82 | ``` 83 | Trying to find: Frame: testFrame1 84 | -- testFrame1 (0x001) 85 | (0000.000000) vcan0 sig0: 0x01 01 86 | (0000.000000) vcan0 sig1: 0x23 35 87 | (0000.000000) vcan0 sig2: 0x00 00 88 | (0000.000000) vcan0 sig3: 0x800 2048 89 | (0000.000000) vcan0 sig4: 0x100 256 90 | (0000.000000) vcan0 sig5: 0x01 01 91 | (0000.000000) vcan0 sig6: 0x00 00 92 | (0000.000000) vcan0 sig7: 0x208 520 93 | (0000.000000) vcan0 sig8: 0x00 00 94 | (0000.000000) vcan0 sig9: 0x00 00 95 | (0000.000000) vcan0 sig10: 0x00 00 96 | ``` 97 | 98 | ``` 99 | echo "(0.0) vcan0 001#8d00100100820100" | ./socketcanDecodeSignal ccl_test.dbc testFrame1 100 | ``` 101 | 102 | ``` 103 | Trying to find: Frame: testFrame2 104 | -- testFrame2 (0x002) 105 | (0000.000001) vcan0 secSig1: 0x00 00 106 | (0000.000001) vcan0 secSig2: 0x00 00 107 | (0000.000001) vcan0 secSig3: 0x00 00 108 | (0000.000001) vcan0 secSig4: 0x02 02 109 | (0000.000001) vcan0 secSig5: 0x00 00 110 | (0000.000001) vcan0 secSig6: 0x00 00 111 | (0000.000001) vcan0 secSig7: 0x00 00 112 | (0000.000001) vcan0 secSig8: 0x03 03 113 | (0000.000001) vcan0 secSig9: 0x01 01 114 | (0000.000001) vcan0 secSig10: 0x500 1280 115 | (0000.000001) vcan0 secSig11: 0xffffffffffffff70 -144 116 | (0000.000001) vcan0 secSig12: 0x0c 12 117 | ``` 118 | -------------------------------------------------------------------------------- /ccl_test.dbc: -------------------------------------------------------------------------------- 1 | VERSION "created by canmatrix" 2 | 3 | 4 | NS_ : 5 | 6 | BS_: 7 | 8 | BU_: 9 | 10 | 11 | BO_ 1 testFrame1: 8 TEST_ECU 12 | SG_ sig0 : 1|2@0+ (1.0,0.0) [0|0] "" CCL_TEST 13 | SG_ sig1 : 7|6@0+ (1.0,0.0) [0|0] "" CCL_TEST 14 | SG_ sig2 : 15|11@0+ (1.0,0.0) [0|0] "" CCL_TEST 15 | SG_ sig3 : 20|12@0+ (1.0,0.0) [0|0] "" CCL_TEST 16 | SG_ sig4 : 24|9@0+ (1.0,0.0) [0|0] "" CCL_TEST 17 | SG_ sig5 : 50|3@0+ (1.0,0.0) [0|0] "" CCL_TEST 18 | SG_ sig6 : 53|3@0+ (1.0,0.0) [0|0] "" CCL_TEST 19 | SG_ sig7 : 47|10@0+ (1.0,0.0) [0|0] "" CCL_TEST 20 | SG_ sig8 : 58|3@0+ (1.0,0.0) [0|0] "" CCL_TEST 21 | SG_ sig9 : 61|3@0+ (1.0,0.0) [0|0] "" CCL_TEST 22 | SG_ sig10 : 63|2@0+ (1.0,0.0) [0|0] "" CCL_TEST 23 | 24 | BO_ 2 testFrame2: 8 TEST_ECU 25 | SG_ secSig1 : 60|2@1+ (1.0,0.0) [0|0] "" CCL_TEST 26 | SG_ secSig2 : 55|1@1+ (1.0,0.0) [0|0] "" CCL_TEST 27 | SG_ secSig3 : 20|4@1+ (1.0,0.0) [0|0] "" CCL_TEST 28 | SG_ secSig4 : 62|2@1+ (1.0,0.0) [0|0] "" CCL_TEST 29 | SG_ secSig5 : 34|3@1+ (1.0,0.0) [0|0] "" CCL_TEST 30 | SG_ secSig6 : 37|3@1+ (1.0,0.0) [0|0] "" CCL_TEST 31 | SG_ secSig7 : 59|1@1- (1.0,0.0) [0|0] "" CCL_TEST 32 | SG_ secSig8 : 56|3@1+ (1.0,0.0) [0|0] "" CCL_TEST 33 | SG_ secSig9 : 52|3@1+ (1.0,0.0) [0|0] "" CCL_TEST 34 | SG_ secSig10 : 8|12@1+ (1.0,0.0) [0|0] "" CCL_TEST 35 | SG_ secSig11 : 24|10@1- (1.0,0.0) [0|0] "" CCL_TEST 36 | SG_ secSig12 : 0|8@1+ (1.0,0.0) [0|0] "" CCL_TEST 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /datenbasis.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "datenbasis.h" 3 | 4 | 5 | void add_frame(struct frame_struct **db, canid_t canID, char *frameName) { 6 | struct frame_struct *s; 7 | s = malloc(sizeof(struct frame_struct)); 8 | s->canID = canID; 9 | s->signals = NULL; 10 | strcpy(s->name, frameName); 11 | s->isMultiplexed = 0; 12 | HASH_ADD_INT( *db, canID, s ); 13 | } 14 | 15 | struct frame_struct *find_frame(struct frame_struct *db, int canID) { 16 | struct frame_struct *s; 17 | HASH_FIND_INT( db, &canID, s ); 18 | return s; 19 | /* s: output pointer */ 20 | } 21 | 22 | struct frame_struct *find_frame_by_name(struct frame_struct *db, char *name) { 23 | struct frame_struct *s; 24 | 25 | for(s=db; s != NULL; s=s->hh.next) { 26 | if(!strcmp(s->name, name)) return s; 27 | } 28 | 29 | return 0; 30 | /* s: output pointer */ 31 | } 32 | 33 | struct signal_struct *find_signal_by_name(struct frame_struct *frame, char *name) { 34 | struct signal_struct *sig; 35 | 36 | for(sig=frame->signals; sig != NULL; sig = sig->hh.next) { 37 | if(!strcmp(sig->name, name)) return sig; 38 | } 39 | 40 | return 0; 41 | } 42 | 43 | struct frame_struct *find_frame_by_signalname(struct frame_struct *db, char *name) { 44 | struct frame_struct *frame; 45 | struct signal_struct *sig; 46 | 47 | for(frame=db; frame != NULL; frame=frame->hh.next) { 48 | for(sig=frame->signals; sig != NULL; sig = sig->hh.next) { 49 | if(!strcmp(sig->name, name)) return frame; 50 | } 51 | } 52 | 53 | return 0; 54 | /* s: output pointer */ 55 | } 56 | 57 | void add_signal(struct frame_struct *db, int frameId, char *signalName, int startBit, int signalLength, int is_big_endian, int signedState, float factor, float offset, float min, float max, char *unit, char *receiverList, unsigned char isMultiplexer, unsigned char muxId) 58 | { 59 | struct frame_struct *frame; 60 | struct signal_struct *newSignal; 61 | 62 | frame = find_frame(db, frameId); 63 | 64 | newSignal = malloc(sizeof(struct signal_struct)); 65 | strcpy(newSignal->name, signalName); 66 | newSignal->startBit = startBit; 67 | newSignal->signalLength = signalLength; 68 | newSignal->is_big_endian = is_big_endian; 69 | newSignal->is_signed = signedState; 70 | newSignal->factor = factor; 71 | newSignal->offset = offset; 72 | newSignal->min = min; 73 | newSignal->max = max; 74 | 75 | 76 | if(isMultiplexer > 0) 77 | { 78 | frame->isMultiplexed = 1; 79 | } 80 | newSignal->isMultiplexer = isMultiplexer; 81 | newSignal->muxId = muxId; 82 | 83 | strcpy(newSignal->unit, unit); 84 | strcpy(newSignal->receiverList, receiverList); 85 | 86 | HASH_ADD_STR( frame->signals, name, newSignal ); 87 | } 88 | 89 | 90 | 91 | int readInDatabase(struct frame_struct **db, char *Filename) 92 | { 93 | char frameName[512], sender[512], line[512]; 94 | char signalName[512],signedState, unit[512], receiverList[512]; 95 | int startBit=0,signalLength=0,byteOrder=0; 96 | float factor=0., offset=0., min=0., max=0.; 97 | char mux[4]; 98 | int muxId = 0; 99 | 100 | int frameId=0, len; 101 | 102 | FILE *fp; 103 | if(!(fp = fopen(Filename,"r"))) 104 | { 105 | fprintf(stderr, "Error opening %s\n", Filename); 106 | return 1; 107 | } 108 | 109 | while(fgets(line,511,fp)) 110 | { 111 | if(sscanf(line," BO_ %d %s %d %s",&frameId,frameName,&len,sender) == 4) 112 | { 113 | frameName[strlen(frameName)-1] = 0; 114 | add_frame(db, frameId, frameName); 115 | } 116 | else if(sscanf(line," SG_ %s : %d|%d@%d%c (%f,%f) [%f|%f] %s %s",signalName, &startBit, &signalLength,&byteOrder, &signedState, &factor, &offset, &min, &max, unit, receiverList ) > 5) 117 | { 118 | if (byteOrder == 0) 119 | { 120 | // following code is from https://github.com/julietkilo/CANBabel/blob/master/src/main/java/com/github/canbabel/canio/dbc/DbcReader.java: 121 | 122 | int pos = 7 - (startBit % 8) + (signalLength - 1); 123 | if (pos < 8) 124 | { 125 | startBit = startBit - signalLength + 1; 126 | } 127 | else 128 | { 129 | int cpos = 7 - (pos % 8); 130 | int bytes = (int)(pos / 8); 131 | startBit = cpos + (bytes * 8) + (int)(startBit/8) * 8; 132 | } 133 | } 134 | add_signal(*db, frameId, signalName, startBit, signalLength, byteOrder == 0, signedState == '-', factor, offset, min, max, unit, receiverList, 0,0); 135 | } 136 | else if(sscanf(line," SG_ %s %s : %d|%d@%d%c (%f,%f) [%f|%f] %s %s",signalName, mux, &startBit, &signalLength,&byteOrder, &signedState, &factor, &offset, &min, &max, unit, receiverList ) > 5) 137 | { 138 | if (byteOrder == 0) 139 | { 140 | // following code is from https://github.com/julietkilo/CANBabel/blob/master/src/main/java/com/github/canbabel/canio/dbc/DbcReader.java: 141 | 142 | int pos = 7 - (startBit % 8) + (signalLength - 1); 143 | if (pos < 8) 144 | { 145 | startBit = startBit - signalLength + 1; 146 | } 147 | else 148 | { 149 | int cpos = 7 - (pos % 8); 150 | int bytes = (int)(pos / 8); 151 | startBit = cpos + (bytes * 8) + (int)(startBit/8) * 8; 152 | } 153 | } 154 | if(mux[0] == 'M') 155 | { 156 | add_signal(*db, frameId, signalName, startBit, signalLength, byteOrder == 0, signedState == '-', factor, offset, min, max, unit, receiverList, 1, 0); 157 | } 158 | else if(mux[0] == 'm') 159 | { 160 | sscanf(mux, "m%d", &muxId); 161 | add_signal(*db, frameId, signalName, startBit, signalLength, byteOrder == 0, signedState == '-', factor, offset, min, max, unit, receiverList, 2, muxId); 162 | 163 | } 164 | 165 | } 166 | } 167 | return 0; 168 | } 169 | -------------------------------------------------------------------------------- /datenbasis.h: -------------------------------------------------------------------------------- 1 | #if !defined _DATENBASIS_H_ 2 | #define _DATENBASIS_H_ 3 | 4 | #include "uthash.h" 5 | 6 | #include 7 | #include 8 | #include "lib.h" 9 | 10 | 11 | struct signal_struct { 12 | char name[80]; 13 | int startBit; 14 | int signalLength; 15 | int is_big_endian; // Intel = 0; Motorola (== BIG Endian) = 1 16 | int is_signed; 17 | float factor; 18 | float offset; 19 | float min; 20 | float max; 21 | char unit[80]; 22 | char receiverList[512]; 23 | __u8 isMultiplexer; 24 | __u8 muxId; 25 | 26 | __u8 number; 27 | UT_hash_handle hh; 28 | }; 29 | 30 | struct frame_struct { 31 | canid_t canID; 32 | char name[80]; 33 | __u8 isMultiplexed; 34 | struct signal_struct *signals; 35 | UT_hash_handle hh; 36 | }; 37 | 38 | 39 | #endif 40 | 41 | 42 | void add_message(struct frame_struct **db, canid_t canID, char *messageName); 43 | struct frame_struct *find_frame(struct frame_struct *db, int canID); 44 | struct frame_struct *find_frame_by_name(struct frame_struct *db, char *name); 45 | struct signal_struct *find_signal_by_name(struct frame_struct *frame, char *name); 46 | struct frame_struct *find_frame_by_signalname(struct frame_struct *db, char *name); 47 | void add_signal(struct frame_struct *db, int frameId, char *signalName, int startBit, int signalLength, int byteOrder, int signedState, float factor, float offset, float min, float max, char *unit, char *receiverList, unsigned char isMultiplexer, unsigned char muxId); 48 | int readInDatabase(struct frame_struct **db, char *Filename); 49 | 50 | -------------------------------------------------------------------------------- /lib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: lib.c 1235 2011-02-14 16:10:39Z wolf $ 3 | */ 4 | 5 | /* 6 | * lib.c - library for command line tools 7 | * 8 | * Copyright (c) 2002-2007 Volkswagen Group Electronic Research 9 | * All rights reserved. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 3. Neither the name of Volkswagen nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software 21 | * without specific prior written permission. 22 | * 23 | * Alternatively, provided that this notice is retained in full, this 24 | * software may be distributed under the terms of the GNU General 25 | * Public License ("GPL") version 2, in which case the provisions of the 26 | * GPL apply INSTEAD OF those given above. 27 | * 28 | * The provided data structures and external interfaces from this code 29 | * are not restricted to be used by modules with a GPL compatible license. 30 | * 31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 34 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 36 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 37 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 38 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 39 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 41 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 42 | * DAMAGE. 43 | * 44 | * Send feedback to 45 | * 46 | */ 47 | 48 | #include 49 | #include 50 | #include 51 | 52 | #include /* for sa_family_t */ 53 | #include 54 | #include 55 | 56 | #include "lib.h" 57 | 58 | #define CANID_DELIM '#' 59 | #define DATA_SEPERATOR '.' 60 | 61 | #define MAX_CANFRAME "12345678#01.23.45.67.89.AB.CD.EF" 62 | #define MAX_LONG_CANFRAME_SIZE 256 63 | 64 | unsigned char asc2nibble(char c) { 65 | 66 | if ((c >= '0') && (c <= '9')) 67 | return c - '0'; 68 | 69 | if ((c >= 'A') && (c <= 'F')) 70 | return c - 'A' + 10; 71 | 72 | if ((c >= 'a') && (c <= 'f')) 73 | return c - 'a' + 10; 74 | 75 | return 16; /* error */ 76 | } 77 | 78 | int hexstring2candata(char *arg, struct can_frame *cf) { 79 | 80 | int len = strlen(arg); 81 | int i; 82 | unsigned char tmp; 83 | 84 | if (!len || len%2 || len > 16) 85 | return 1; 86 | 87 | for (i=0; i < len/2; i++) { 88 | 89 | tmp = asc2nibble(*(arg+(2*i))); 90 | if (tmp > 0x0F) 91 | return 1; 92 | 93 | cf->data[i] = (tmp << 4); 94 | 95 | tmp = asc2nibble(*(arg+(2*i)+1)); 96 | if (tmp > 0x0F) 97 | return 1; 98 | 99 | cf->data[i] |= tmp; 100 | } 101 | 102 | return 0; 103 | } 104 | 105 | int parse_canframe(char *cs, struct can_frame *cf) { 106 | /* documentation see lib.h */ 107 | 108 | int i, idx, dlc, len; 109 | unsigned char tmp; 110 | 111 | len = strlen(cs); 112 | //printf("'%s' len %d\n", cs, len); 113 | 114 | memset(cf, 0, sizeof(*cf)); /* init CAN frame, e.g. DLC = 0 */ 115 | 116 | if (len < 4) 117 | return 1; 118 | 119 | if (cs[3] == CANID_DELIM) { /* 3 digits */ 120 | 121 | idx = 4; 122 | for (i=0; i<3; i++){ 123 | if ((tmp = asc2nibble(cs[i])) > 0x0F) 124 | return 1; 125 | cf->can_id |= (tmp << (2-i)*4); 126 | } 127 | 128 | } else if (cs[8] == CANID_DELIM) { /* 8 digits */ 129 | 130 | idx = 9; 131 | for (i=0; i<8; i++){ 132 | if ((tmp = asc2nibble(cs[i])) > 0x0F) 133 | return 1; 134 | cf->can_id |= (tmp << (7-i)*4); 135 | } 136 | if (!(cf->can_id & CAN_ERR_FLAG)) /* 8 digits but no errorframe? */ 137 | cf->can_id |= CAN_EFF_FLAG; /* then it is an extended frame */ 138 | 139 | } else 140 | return 1; 141 | 142 | if((cs[idx] == 'R') || (cs[idx] == 'r')){ /* RTR frame */ 143 | cf->can_id |= CAN_RTR_FLAG; 144 | return 0; 145 | } 146 | 147 | for (i=0, dlc=0; i<8; i++){ 148 | 149 | if(cs[idx] == DATA_SEPERATOR) /* skip (optional) seperator */ 150 | idx++; 151 | 152 | if(idx >= len) /* end of string => end of data */ 153 | break; 154 | 155 | if ((tmp = asc2nibble(cs[idx++])) > 0x0F) 156 | return 1; 157 | cf->data[i] = (tmp << 4); 158 | if ((tmp = asc2nibble(cs[idx++])) > 0x0F) 159 | return 1; 160 | cf->data[i] |= tmp; 161 | dlc++; 162 | } 163 | 164 | cf->can_dlc = dlc; 165 | 166 | return 0; 167 | } 168 | 169 | void fprint_canframe(FILE *stream , struct can_frame *cf, char *eol, int sep) { 170 | /* documentation see lib.h */ 171 | 172 | char buf[sizeof(MAX_CANFRAME)+1]; /* max length */ 173 | 174 | sprint_canframe(buf, cf, sep); 175 | fprintf(stream, "%s", buf); 176 | if (eol) 177 | fprintf(stream, "%s", eol); 178 | } 179 | 180 | void sprint_canframe(char *buf , struct can_frame *cf, int sep) { 181 | /* documentation see lib.h */ 182 | 183 | int i,offset; 184 | int dlc = (cf->can_dlc > 8)? 8 : cf->can_dlc; 185 | 186 | if (cf->can_id & CAN_ERR_FLAG) { 187 | sprintf(buf, "%08X#", cf->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG)); 188 | offset = 9; 189 | } else if (cf->can_id & CAN_EFF_FLAG) { 190 | sprintf(buf, "%08X#", cf->can_id & CAN_EFF_MASK); 191 | offset = 9; 192 | } else { 193 | sprintf(buf, "%03X#", cf->can_id & CAN_SFF_MASK); 194 | offset = 4; 195 | } 196 | 197 | if (cf->can_id & CAN_RTR_FLAG) /* there are no ERR frames with RTR */ 198 | sprintf(buf+offset, "R"); 199 | else 200 | for (i = 0; i < dlc; i++) { 201 | sprintf(buf+offset, "%02X", cf->data[i]); 202 | offset += 2; 203 | if (sep && (i+1 < dlc)) 204 | sprintf(buf+offset++, "."); 205 | } 206 | 207 | 208 | } 209 | 210 | void fprint_long_canframe(FILE *stream , struct can_frame *cf, char *eol, int view) { 211 | /* documentation see lib.h */ 212 | 213 | char buf[MAX_LONG_CANFRAME_SIZE]; 214 | 215 | sprint_long_canframe(buf, cf, view); 216 | fprintf(stream, "%s", buf); 217 | if ((view & CANLIB_VIEW_ERROR) && (cf->can_id & CAN_ERR_FLAG)) { 218 | snprintf_can_error_frame(buf, sizeof(buf), cf, "\n\t"); 219 | fprintf(stream, "\n\t%s", buf); 220 | } 221 | if (eol) 222 | fprintf(stream, "%s", eol); 223 | } 224 | 225 | void sprint_long_canframe(char *buf , struct can_frame *cf, int view) { 226 | /* documentation see lib.h */ 227 | 228 | int i, j, dlen, offset; 229 | int dlc = (cf->can_dlc > 8)? 8 : cf->can_dlc; 230 | 231 | if (cf->can_id & CAN_ERR_FLAG) { 232 | sprintf(buf, "%8X ", cf->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG)); 233 | offset = 10; 234 | } else if (cf->can_id & CAN_EFF_FLAG) { 235 | sprintf(buf, "%8X ", cf->can_id & CAN_EFF_MASK); 236 | offset = 10; 237 | } else { 238 | sprintf(buf, "%3X ", cf->can_id & CAN_SFF_MASK); 239 | offset = 5; 240 | } 241 | 242 | sprintf(buf+offset, "[%d]", dlc); 243 | offset += 3; 244 | 245 | if (cf->can_id & CAN_RTR_FLAG) { /* there are no ERR frames with RTR */ 246 | sprintf(buf+offset, " remote request"); 247 | return; 248 | } 249 | 250 | if (view & CANLIB_VIEW_BINARY) { 251 | dlen = 9; /* _10101010 */ 252 | if (view & CANLIB_VIEW_SWAP) { 253 | for (i = dlc - 1; i >= 0; i--) { 254 | buf[offset++] = (i == dlc-1)?' ':SWAP_DELIMITER; 255 | for (j = 7; j >= 0; j--) 256 | buf[offset++] = (1<data[i])?'1':'0'; 257 | } 258 | } else { 259 | for (i = 0; i < dlc; i++) { 260 | buf[offset++] = ' '; 261 | for (j = 7; j >= 0; j--) 262 | buf[offset++] = (1<data[i])?'1':'0'; 263 | } 264 | } 265 | buf[offset] = 0; /* terminate string */ 266 | } else { 267 | dlen = 3; /* _AA */ 268 | if (view & CANLIB_VIEW_SWAP) { 269 | for (i = dlc - 1; i >= 0; i--) { 270 | sprintf(buf+offset, "%c%02X", 271 | (i == dlc-1)?' ':SWAP_DELIMITER, 272 | cf->data[i]); 273 | offset += dlen; 274 | } 275 | } else { 276 | for (i = 0; i < dlc; i++) { 277 | sprintf(buf+offset, " %02X", cf->data[i]); 278 | offset += dlen; 279 | } 280 | } 281 | } 282 | 283 | if (cf->can_id & CAN_ERR_FLAG) 284 | sprintf(buf+offset, "%*s", dlen*(8-dlc)+13, "ERRORFRAME"); 285 | else if (view & CANLIB_VIEW_ASCII) { 286 | j = dlen*(8-dlc)+4; 287 | if (view & CANLIB_VIEW_SWAP) { 288 | sprintf(buf+offset, "%*s", j, "`"); 289 | offset += j; 290 | for (i = dlc - 1; i >= 0; i--) 291 | if ((cf->data[i] > 0x1F) && (cf->data[i] < 0x7F)) 292 | buf[offset++] = cf->data[i]; 293 | else 294 | buf[offset++] = '.'; 295 | 296 | sprintf(buf+offset, "`"); 297 | } else { 298 | sprintf(buf+offset, "%*s", j, "'"); 299 | offset += j; 300 | for (i = 0; i < dlc; i++) 301 | if ((cf->data[i] > 0x1F) && (cf->data[i] < 0x7F)) 302 | buf[offset++] = cf->data[i]; 303 | else 304 | buf[offset++] = '.'; 305 | 306 | sprintf(buf+offset, "'"); 307 | } 308 | } 309 | } 310 | 311 | static const char *error_classes[] = { 312 | "tx-timeout", 313 | "lost-arbitration", 314 | "controller-problem", 315 | "protocol-violation", 316 | "transceiver-status", 317 | "no-acknowledgement-on-tx", 318 | "bus-off", 319 | "bus-error", 320 | "restarted-after-bus-off", 321 | }; 322 | 323 | static const char *controller_problems[] = { 324 | "rx-overflow", 325 | "tx-overflow", 326 | "rx-error-warning", 327 | "tx-error-warning", 328 | "rx-error-passive", 329 | "tx-error-passive", 330 | }; 331 | 332 | static const char *protocol_violation_types[] = { 333 | "single-bit-error", 334 | "frame-format-error", 335 | "bit-stuffing-error", 336 | "tx-dominant-bit-error", 337 | "tx-recessive-bit-error", 338 | "bus-overload", 339 | "back-to-error-active", 340 | "error-on-tx", 341 | }; 342 | 343 | static const char *protocol_violation_locations[] = { 344 | "unspecified", 345 | "unspecified", 346 | "id.28-to-id.28", 347 | "start-of-frame", 348 | "bit-srtr", 349 | "bit-ide", 350 | "id.20-to-id.18", 351 | "id.17-to-id.13", 352 | "crc-sequence", 353 | "reserved-bit-0", 354 | "data-field", 355 | "data-length-code", 356 | "bit-rtr", 357 | "reserved-bit-1", 358 | "id.4-to-id.0", 359 | "id.12-to-id.5", 360 | "unspecified", 361 | "active-error-flag", 362 | "intermission", 363 | "tolerate-dominant-bits", 364 | "unspecified", 365 | "unspecified", 366 | "passive-error-flag", 367 | "error-delimiter", 368 | "crc-delimiter", 369 | "acknowledge-slot", 370 | "end-of-frame", 371 | "acknowledge-delimiter", 372 | "overload-flag", 373 | "unspecified", 374 | "unspecified", 375 | "unspecified", 376 | }; 377 | 378 | #ifndef ARRAY_SIZE 379 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 380 | #endif 381 | 382 | static int snprintf_error_data(char *buf, size_t len, uint8_t err, 383 | const char **arr, int arr_len) 384 | { 385 | int i, n = 0, count = 0; 386 | 387 | if (!err || len <= 0) 388 | return 0; 389 | 390 | for (i = 0; i < arr_len; i++) { 391 | if (err & (1 << i)) { 392 | if (count) 393 | n += snprintf(buf + n, len - n, ","); 394 | n += snprintf(buf + n, len - n, "%s", arr[i]); 395 | count++; 396 | } 397 | } 398 | 399 | return n; 400 | } 401 | 402 | static int snprintf_error_lostarb(char *buf, size_t len, struct can_frame *cf) 403 | { 404 | if (len <= 0) 405 | return 0; 406 | return snprintf(buf, len, "{at bit %d}", cf->data[0]); 407 | } 408 | 409 | static int snprintf_error_ctrl(char *buf, size_t len, struct can_frame *cf) 410 | { 411 | int n = 0; 412 | 413 | if (len <= 0) 414 | return 0; 415 | 416 | n += snprintf(buf + n, len - n, "{"); 417 | n += snprintf_error_data(buf + n, len - n, cf->data[1], 418 | controller_problems, 419 | ARRAY_SIZE(controller_problems)); 420 | n += snprintf(buf + n, len - n, "}"); 421 | 422 | return n; 423 | } 424 | 425 | static int snprintf_error_prot(char *buf, size_t len, struct can_frame *cf) 426 | { 427 | int n = 0; 428 | 429 | if (len <= 0) 430 | return 0; 431 | 432 | n += snprintf(buf + n, len - n, "{{"); 433 | n += snprintf_error_data(buf + n, len - n, cf->data[2], 434 | protocol_violation_types, 435 | ARRAY_SIZE(protocol_violation_types)); 436 | n += snprintf(buf + n, len - n, "}{"); 437 | if (cf->data[3] > 0 && 438 | cf->data[3] < ARRAY_SIZE(protocol_violation_locations)) 439 | n += snprintf(buf + n, len - n, "%s", 440 | protocol_violation_locations[cf->data[3]]); 441 | n += snprintf(buf + n, len - n, "}}"); 442 | 443 | return n; 444 | } 445 | 446 | void snprintf_can_error_frame(char *buf, size_t len, struct can_frame *cf, 447 | char* sep) 448 | { 449 | canid_t class, mask; 450 | int i, n = 0, classes = 0; 451 | char *defsep = ","; 452 | 453 | if (!(cf->can_id & CAN_ERR_FLAG)) 454 | return; 455 | 456 | class = cf->can_id & CAN_EFF_MASK; 457 | if (class > (1 << ARRAY_SIZE(error_classes))) { 458 | fprintf(stderr, "Error class %#x is invalid\n", class); 459 | return; 460 | } 461 | 462 | if (!sep) 463 | sep = defsep; 464 | 465 | for (i = 0; i < ARRAY_SIZE(error_classes); i++) { 466 | mask = 1 << i; 467 | if (class & mask) { 468 | if (classes) 469 | n += snprintf(buf + n, len - n, "%s", sep); 470 | n += snprintf(buf + n, len - n, "%s", error_classes[i]); 471 | if (mask == CAN_ERR_LOSTARB) 472 | n += snprintf_error_lostarb(buf + n, len - n, 473 | cf); 474 | if (mask == CAN_ERR_CRTL) 475 | n += snprintf_error_ctrl(buf + n, len - n, cf); 476 | if (mask == CAN_ERR_PROT) 477 | n += snprintf_error_prot(buf + n, len - n, cf); 478 | classes++; 479 | } 480 | } 481 | 482 | if (cf->data[6] || cf->data[7]) { 483 | n += snprintf(buf + n, len - n, "%s", sep); 484 | n += snprintf(buf + n, len - n, "error-counter-tx-rx{{%d}{%d}}", 485 | cf->data[6], cf->data[7]); 486 | } 487 | } 488 | -------------------------------------------------------------------------------- /lib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: lib.h 1235 2011-02-14 16:10:39Z wolf $ 3 | */ 4 | 5 | /* 6 | * lib.h - library include for command line tools 7 | * 8 | * Copyright (c) 2002-2007 Volkswagen Group Electronic Research 9 | * All rights reserved. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 3. Neither the name of Volkswagen nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software 21 | * without specific prior written permission. 22 | * 23 | * Alternatively, provided that this notice is retained in full, this 24 | * software may be distributed under the terms of the GNU General 25 | * Public License ("GPL") version 2, in which case the provisions of the 26 | * GPL apply INSTEAD OF those given above. 27 | * 28 | * The provided data structures and external interfaces from this code 29 | * are not restricted to be used by modules with a GPL compatible license. 30 | * 31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 34 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 36 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 37 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 38 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 39 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 41 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 42 | * DAMAGE. 43 | * 44 | * Send feedback to 45 | * 46 | */ 47 | 48 | unsigned char asc2nibble(char c); 49 | /* 50 | * Returns the decimal value of a given ASCII hex character. 51 | * 52 | * While 0..9, a..f, A..F are valid ASCII hex characters. 53 | * On invalid characters the value 16 is returned for error handling. 54 | */ 55 | 56 | int hexstring2candata(char *arg, struct can_frame *cf); 57 | /* 58 | * Converts a given ASCII hex string to values in the can_frame data[]. 59 | * 60 | * A valid ASCII hex string consists of an even number of up to 16 chars. 61 | * Leading zeros '00' in the ASCII hex string are interpreted. 62 | * 63 | * Examples: 64 | * 65 | * "1234" => data[0] = 0x12, data[1] = 0x34 66 | * "001234" => data[0] = 0x00, data[1] = 0x12, data[2] = 0x34 67 | * 68 | * Return values: 69 | * 0 = success 70 | * 1 = error (in length or the given characters are no ASCII hex characters) 71 | * 72 | * Remark: The not written data[] elements remain unchanged. 73 | * 74 | */ 75 | 76 | int parse_canframe(char *cs, struct can_frame *cf); 77 | /* 78 | * Transfers a valid ASCII string decribing a CAN frame into struct can_frame. 79 | * 80 | * #{R|data} 81 | * 82 | * can_id can have 3 (standard frame format) or 8 (extended frame format) 83 | * hexadecimal chars 84 | * 85 | * data has 0 to 8 hex-values that can (optionally) be seperated by '.' 86 | * 87 | * Examples: 88 | * 89 | * 123# -> standard CAN-Id = 0x123, dlc = 0 90 | * 12345678# -> extended CAN-Id = 0x12345678, dlc = 0 91 | * 123#R -> standard CAN-Id = 0x123, dlc = 0, RTR-frame 92 | * 7A1#r -> standard CAN-Id = 0x7A1, dlc = 0, RTR-frame 93 | * 94 | * 123#00 -> standard CAN-Id = 0x123, dlc = 1, data[0] = 0x00 95 | * 123#1122334455667788 -> standard CAN-Id = 0x123, dlc = 8 96 | * 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, dlc = 8 97 | * 123#11.2233.44556677.88 -> standard CAN-Id = 0x123, dlc = 8 98 | * 32345678#112233 -> error frame with CAN_ERR_FLAG (0x2000000) set 99 | * 100 | * Simple facts on this compact ASCII CAN frame representation: 101 | * 102 | * - 3 digits: standard frame format 103 | * - 8 digits: extendend frame format OR error frame 104 | * - 8 digits with CAN_ERR_FLAG (0x2000000) set: error frame 105 | * - an error frame is never a RTR frame 106 | * 107 | */ 108 | 109 | void fprint_canframe(FILE *stream , struct can_frame *cf, char *eol, int sep); 110 | void sprint_canframe(char *buf , struct can_frame *cf, int sep); 111 | /* 112 | * Creates a CAN frame hexadecimal output in compact format. 113 | * The CAN data[] is seperated by '.' when sep != 0. 114 | * 115 | * 12345678#112233 -> exended CAN-Id = 0x12345678, dlc = 3, data, sep = 0 116 | * 12345678#R -> exended CAN-Id = 0x12345678, RTR 117 | * 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, dlc = 8, sep = 1 118 | * 32345678#112233 -> error frame with CAN_ERR_FLAG (0x2000000) set 119 | * 120 | * Examples: 121 | * 122 | * fprint_canframe(stdout, &frame, "\n", 0); // with eol to STDOUT 123 | * fprint_canframe(stderr, &frame, NULL, 0); // no eol to STDERR 124 | * 125 | */ 126 | 127 | #define CANLIB_VIEW_ASCII 0x1 128 | #define CANLIB_VIEW_BINARY 0x2 129 | #define CANLIB_VIEW_SWAP 0x4 130 | #define CANLIB_VIEW_ERROR 0x8 131 | 132 | #define SWAP_DELIMITER '`' 133 | 134 | void fprint_long_canframe(FILE *stream , struct can_frame *cf, char *eol, int view); 135 | void sprint_long_canframe(char *buf , struct can_frame *cf, int view); 136 | /* 137 | * Creates a CAN frame hexadecimal output in user readable format. 138 | * 139 | * 12345678 [3] 11 22 33 -> exended CAN-Id = 0x12345678, dlc = 3, data 140 | * 12345678 [0] remote request -> exended CAN-Id = 0x12345678, RTR 141 | * 14B0DC51 [8] 4A 94 E8 2A EC 58 55 62 'J..*.XUb' -> (with ASCII output) 142 | * 20001111 [7] C6 23 7B 32 69 98 3C ERRORFRAME -> (CAN_ERR_FLAG set) 143 | * 144 | * Examples: 145 | * 146 | * fprint_long_canframe(stdout, &frame, "\n", 0); // with eol to STDOUT 147 | * fprint_long_canframe(stderr, &frame, NULL, 0); // no eol to STDERR 148 | * 149 | */ 150 | 151 | void snprintf_can_error_frame(char *buf, size_t len, struct can_frame *cf, 152 | char *sep); 153 | /* 154 | * Creates a CAN error frame output in user readable format. 155 | */ 156 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "datenbasis.h" 4 | #include "processFrame.h" 5 | 6 | // echo "(0.0) vcan0 001#8d00100100820100" | ./socketcanDecodeSignal ccl_test.dbc testFrame1 7 | // echo "(0.1) vcan0 002#0C00057003CD1F83" | ./socketcanDecodeSignal ccl_test.dbc testFrame2 8 | void printCallback(char *name, __u64 rawValue, double scaledValue, 9 | struct timeval tv, char *device) 10 | { 11 | printf("(%04ld.%06ld) %s %s: 0x%02llx %02.0f \n", tv.tv_sec, tv.tv_usec, 12 | device, name, rawValue, scaledValue); 13 | } 14 | 15 | int main(int argc, char **argv) 16 | { 17 | char buf[100], device[100], ascframe[100]; 18 | 19 | char *frameName, *signalName; 20 | struct can_frame cf; 21 | 22 | struct frame_struct *dataBase = NULL; 23 | struct signal_callback_list *callbackList = NULL; 24 | 25 | struct signal_struct *mySignal; 26 | struct frame_struct *myFrame; 27 | struct timeval tv; 28 | 29 | if (argc < 2) 30 | { 31 | fprintf(stderr, "Usage:\n"); 32 | fprintf(stderr, 33 | "%s Database Message1.Signal1 [Message2.Signal2 Message3.Signal3]\n", 34 | argv[0]); 35 | exit(1); 36 | } 37 | 38 | // read dbc 39 | if (readInDatabase(&dataBase, argv[1])) 40 | { 41 | fprintf(stderr, "Error opening Database %s\n", argv[1]); 42 | exit(1); 43 | } 44 | argc--; 45 | argv++; 46 | 47 | // parse arguments (frames/signals which should be decoded) 48 | while (argc >= 2) 49 | { 50 | 51 | frameName = argv[1]; 52 | signalName = strchr(argv[1], '.'); 53 | 54 | printf("Trying to find: Frame: %s", frameName); 55 | if (signalName != NULL) 56 | { 57 | *signalName = 0; 58 | signalName++; 59 | printf(", Signal: %s", signalName); 60 | } 61 | printf("\n"); 62 | myFrame = find_frame_by_name(dataBase, frameName); 63 | 64 | if (!myFrame) 65 | { 66 | fprintf(stderr, "Error finding Frame %s\n", frameName); 67 | exit(1); 68 | } 69 | 70 | if (NULL != signalName) 71 | { 72 | mySignal = find_signal_by_name(myFrame, signalName); 73 | if (!mySignal) 74 | { 75 | fprintf(stderr, "Error finding Signal %s\n", signalName); 76 | exit(1); 77 | } 78 | } 79 | else 80 | { 81 | mySignal = NULL; 82 | } 83 | add_callback(&callbackList, myFrame, mySignal, printCallback, 0); 84 | 85 | printf("-- %s (0x%03x) ", myFrame->name, myFrame->canID); 86 | if (signalName != NULL) 87 | printf(" %s (%d [%d]) --", mySignal->name, mySignal->startBit, 88 | mySignal->signalLength); 89 | printf("\n"); 90 | argc--; 91 | argv++; 92 | } 93 | 94 | while (fgets(buf, 99, stdin)) 95 | { 96 | 97 | if (sscanf(buf, "(%ld.%ld) %s %s", &tv.tv_sec, &tv.tv_usec, device, 98 | ascframe) != 4) 99 | { 100 | fprintf(stderr, "incorrect line format in logfile\n"); 101 | return 1; 102 | } 103 | 104 | if (parse_canframe(ascframe, &cf)) 105 | { 106 | return 1; 107 | } 108 | processFrame(callbackList, &cf, tv, device); 109 | } 110 | 111 | return 0; 112 | } 113 | -------------------------------------------------------------------------------- /processFrame.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "processFrame.h" 3 | #include "stdbool.h" 4 | #include "libcan-encode-decode/include/can_encode_decode_inl.h" 5 | 6 | float toPhysicalValue(uint64_t target, float factor, float offset, 7 | bool is_signed); 8 | uint64_t extractSignal(const uint8_t* frame, const uint8_t startbit, const uint8_t length, bool is_big_endian, bool is_signed); 9 | 10 | void add_callback(struct signal_callback_list **callbackList, struct frame_struct *frame, struct signal_struct *signal, 11 | void (*callback)(char *, __u64, double, struct timeval, char *device), __u8 onChange) 12 | { 13 | 14 | struct signal_callback_list *callbackItem; 15 | 16 | callbackItem = malloc(sizeof(struct signal_callback_list)); 17 | callbackItem->frame = frame; 18 | callbackItem->signal = signal; 19 | callbackItem->callback = callback; 20 | callbackItem->rawValue = 0; 21 | callbackItem->onChange = onChange; 22 | 23 | HASH_ADD_INT(*callbackList, signal, callbackItem); 24 | } 25 | 26 | void processFrame(struct signal_callback_list *callbackList, struct can_frame *cf, struct timeval tv, char *device) 27 | { 28 | struct signal_callback_list *callbackItem; 29 | struct signal_struct *signal; 30 | __u64 value = 0; 31 | double scaled = 0.; 32 | unsigned int muxerVal = 0; 33 | 34 | for (callbackItem = callbackList; callbackItem != NULL; callbackItem = callbackItem->hh.next) 35 | { 36 | if (callbackItem->frame->canID == cf->can_id) 37 | { 38 | if (callbackItem->frame->isMultiplexed) 39 | { 40 | // find multiplexer: 41 | for (signal = callbackItem->frame->signals; signal != NULL; signal = signal->hh.next) 42 | { 43 | if (1 == signal->isMultiplexer) 44 | { 45 | muxerVal = extractSignal(cf->data, signal->startBit, signal->signalLength, (bool) signal->is_big_endian, signal->is_signed); 46 | scaled = toPhysicalValue(muxerVal, signal->factor, signal->offset, signal->is_signed); 47 | (callbackItem->callback)(signal->name, muxerVal, scaled, tv, device); 48 | break; 49 | } 50 | } 51 | } 52 | 53 | if (callbackItem->signal == NULL) 54 | { 55 | if (callbackItem->frame->isMultiplexed) 56 | { 57 | for (signal = callbackItem->frame->signals; signal != NULL; signal = signal->hh.next) 58 | { 59 | // decode not multiplexed signals and signals with correct muxVal 60 | if (0 == signal->isMultiplexer || (2 == signal->isMultiplexer && signal->muxId == muxerVal)) 61 | { 62 | value = extractSignal(cf->data, signal->startBit, signal->signalLength, (bool) signal->is_big_endian, signal->is_signed); 63 | scaled = toPhysicalValue(value, signal->factor, signal->offset, signal->is_signed); 64 | (callbackItem->callback)(signal->name, value, scaled, tv, device); 65 | } 66 | } 67 | 68 | } 69 | else 70 | { 71 | for (signal = callbackItem->frame->signals; signal != NULL; signal = signal->hh.next) 72 | { 73 | value = extractSignal(cf->data, signal->startBit, signal->signalLength, (bool) signal->is_big_endian, signal->is_signed); 74 | scaled = toPhysicalValue(value, signal->factor, signal->offset, signal->is_signed); 75 | (callbackItem->callback)(signal->name, value, scaled, tv, device); 76 | } 77 | } 78 | } 79 | else 80 | { 81 | if (callbackItem->frame->isMultiplexed) 82 | { 83 | if (0 == callbackItem->signal->isMultiplexer || (2 == callbackItem->signal->isMultiplexer && callbackItem->signal->muxId == muxerVal)) 84 | { 85 | value = extractSignal(cf->data, callbackItem->signal->startBit, callbackItem->signal->signalLength, (bool) callbackItem->signal->is_big_endian, 86 | callbackItem->signal->is_signed); 87 | scaled = toPhysicalValue(value, callbackItem->signal->factor, callbackItem->signal->offset, callbackItem->signal->is_signed); 88 | callbackItem->rawValue = value; 89 | (callbackItem->callback)(callbackItem->signal->name, value, scaled, tv, device); 90 | } 91 | } 92 | else 93 | { 94 | if ((0 == callbackItem->onChange) || (callbackItem->rawValue != value)) 95 | { 96 | value = extractSignal(cf->data, callbackItem->signal->startBit, callbackItem->signal->signalLength, (bool) callbackItem->signal->is_big_endian, 97 | callbackItem->signal->is_signed); 98 | scaled = toPhysicalValue(value, callbackItem->signal->factor, callbackItem->signal->offset, callbackItem->signal->is_signed); 99 | callbackItem->rawValue = value; 100 | (callbackItem->callback)(callbackItem->signal->name, value, scaled, tv, device); 101 | } 102 | } 103 | } 104 | } 105 | } 106 | } 107 | 108 | 109 | -------------------------------------------------------------------------------- /processFrame.h: -------------------------------------------------------------------------------- 1 | 2 | #if !defined _PROCESSFRAME_H_ 3 | #define _PROCESSFRAME_H_ 4 | 5 | #include "datenbasis.h" 6 | 7 | struct signal_callback_list { 8 | struct frame_struct *frame; 9 | struct signal_struct *signal; 10 | __u64 rawValue; 11 | __u8 onChange; /* Callback every Signal/Message (0) or only on change of Signal (1) */ 12 | void (*callback)(char *, __u64, double, struct timeval, char *device); 13 | UT_hash_handle hh; 14 | }; 15 | 16 | void add_callback(struct signal_callback_list **callbackList, 17 | struct frame_struct *frame, struct signal_struct *signal, 18 | void (*callback)(char *, __u64, double, struct timeval, char *device), __u8 onChange); 19 | 20 | void processFrame(struct signal_callback_list *callbackList, struct can_frame *cf, struct timeval tv, char *device); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /uthash.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003-2011, Troy D. Hanson http://uthash.sourceforge.net 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 12 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 13 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 14 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 15 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 16 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 18 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 19 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | #ifndef UTHASH_H 25 | #define UTHASH_H 26 | 27 | #include /* memcmp,strlen */ 28 | #include /* ptrdiff_t */ 29 | #include /* exit() */ 30 | 31 | /* These macros use decltype or the earlier __typeof GNU extension. 32 | As decltype is only available in newer compilers (VS2010 or gcc 4.3+ 33 | when compiling c++ source) this code uses whatever method is needed 34 | or, for VS2008 where neither is available, uses casting workarounds. */ 35 | #ifdef _MSC_VER /* MS compiler */ 36 | #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ 37 | #define DECLTYPE(x) (decltype(x)) 38 | #else /* VS2008 or older (or VS2010 in C mode) */ 39 | #define NO_DECLTYPE 40 | #define DECLTYPE(x) 41 | #endif 42 | #else /* GNU, Sun and other compilers */ 43 | #define DECLTYPE(x) (__typeof(x)) 44 | #endif 45 | 46 | #ifdef NO_DECLTYPE 47 | #define DECLTYPE_ASSIGN(dst,src) \ 48 | do { \ 49 | char **_da_dst = (char**)(&(dst)); \ 50 | *_da_dst = (char*)(src); \ 51 | } while(0) 52 | #else 53 | #define DECLTYPE_ASSIGN(dst,src) \ 54 | do { \ 55 | (dst) = DECLTYPE(dst)(src); \ 56 | } while(0) 57 | #endif 58 | 59 | /* a number of the hash function use uint32_t which isn't defined on win32 */ 60 | #ifdef _MSC_VER 61 | typedef unsigned int uint32_t; 62 | typedef unsigned char uint8_t; 63 | #else 64 | #include /* uint32_t */ 65 | #endif 66 | 67 | #define UTHASH_VERSION 1.9.4 68 | 69 | #define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ 70 | #define uthash_malloc(sz) malloc(sz) /* malloc fcn */ 71 | #define uthash_free(ptr,sz) free(ptr) /* free fcn */ 72 | 73 | #define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ 74 | #define uthash_expand_fyi(tbl) /* can be defined to log expands */ 75 | 76 | /* initial number of buckets */ 77 | #define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ 78 | #define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ 79 | #define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ 80 | 81 | /* calculate the element whose hash handle address is hhe */ 82 | #define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) 83 | 84 | #define HASH_FIND(hh,head,keyptr,keylen,out) \ 85 | do { \ 86 | unsigned _hf_bkt,_hf_hashv; \ 87 | out=NULL; \ 88 | if (head) { \ 89 | HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ 90 | if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ 91 | HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ 92 | keyptr,keylen,out); \ 93 | } \ 94 | } \ 95 | } while (0) 96 | 97 | #ifdef HASH_BLOOM 98 | #define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) 99 | #define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) 100 | #define HASH_BLOOM_MAKE(tbl) \ 101 | do { \ 102 | (tbl)->bloom_nbits = HASH_BLOOM; \ 103 | (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ 104 | if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ 105 | memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ 106 | (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ 107 | } while (0); 108 | 109 | #define HASH_BLOOM_FREE(tbl) \ 110 | do { \ 111 | uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ 112 | } while (0); 113 | 114 | #define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) 115 | #define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) 116 | 117 | #define HASH_BLOOM_ADD(tbl,hashv) \ 118 | HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) 119 | 120 | #define HASH_BLOOM_TEST(tbl,hashv) \ 121 | HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) 122 | 123 | #else 124 | #define HASH_BLOOM_MAKE(tbl) 125 | #define HASH_BLOOM_FREE(tbl) 126 | #define HASH_BLOOM_ADD(tbl,hashv) 127 | #define HASH_BLOOM_TEST(tbl,hashv) (1) 128 | #endif 129 | 130 | #define HASH_MAKE_TABLE(hh,head) \ 131 | do { \ 132 | (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ 133 | sizeof(UT_hash_table)); \ 134 | if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ 135 | memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ 136 | (head)->hh.tbl->tail = &((head)->hh); \ 137 | (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ 138 | (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ 139 | (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ 140 | (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ 141 | HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ 142 | if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ 143 | memset((head)->hh.tbl->buckets, 0, \ 144 | HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ 145 | HASH_BLOOM_MAKE((head)->hh.tbl); \ 146 | (head)->hh.tbl->signature = HASH_SIGNATURE; \ 147 | } while(0) 148 | 149 | #define HASH_ADD(hh,head,fieldname,keylen_in,add) \ 150 | HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add) 151 | 152 | #define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ 153 | do { \ 154 | unsigned _ha_bkt; \ 155 | (add)->hh.next = NULL; \ 156 | (add)->hh.key = (char*)keyptr; \ 157 | (add)->hh.keylen = keylen_in; \ 158 | if (!(head)) { \ 159 | head = (add); \ 160 | (head)->hh.prev = NULL; \ 161 | HASH_MAKE_TABLE(hh,head); \ 162 | } else { \ 163 | (head)->hh.tbl->tail->next = (add); \ 164 | (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ 165 | (head)->hh.tbl->tail = &((add)->hh); \ 166 | } \ 167 | (head)->hh.tbl->num_items++; \ 168 | (add)->hh.tbl = (head)->hh.tbl; \ 169 | HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ 170 | (add)->hh.hashv, _ha_bkt); \ 171 | HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ 172 | HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ 173 | HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ 174 | HASH_FSCK(hh,head); \ 175 | } while(0) 176 | 177 | #define HASH_TO_BKT( hashv, num_bkts, bkt ) \ 178 | do { \ 179 | bkt = ((hashv) & ((num_bkts) - 1)); \ 180 | } while(0) 181 | 182 | /* delete "delptr" from the hash table. 183 | * "the usual" patch-up process for the app-order doubly-linked-list. 184 | * The use of _hd_hh_del below deserves special explanation. 185 | * These used to be expressed using (delptr) but that led to a bug 186 | * if someone used the same symbol for the head and deletee, like 187 | * HASH_DELETE(hh,users,users); 188 | * We want that to work, but by changing the head (users) below 189 | * we were forfeiting our ability to further refer to the deletee (users) 190 | * in the patch-up process. Solution: use scratch space to 191 | * copy the deletee pointer, then the latter references are via that 192 | * scratch pointer rather than through the repointed (users) symbol. 193 | */ 194 | #define HASH_DELETE(hh,head,delptr) \ 195 | do { \ 196 | unsigned _hd_bkt; \ 197 | struct UT_hash_handle *_hd_hh_del; \ 198 | if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ 199 | uthash_free((head)->hh.tbl->buckets, \ 200 | (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ 201 | HASH_BLOOM_FREE((head)->hh.tbl); \ 202 | uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ 203 | head = NULL; \ 204 | } else { \ 205 | _hd_hh_del = &((delptr)->hh); \ 206 | if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ 207 | (head)->hh.tbl->tail = \ 208 | (UT_hash_handle*)((char*)((delptr)->hh.prev) + \ 209 | (head)->hh.tbl->hho); \ 210 | } \ 211 | if ((delptr)->hh.prev) { \ 212 | ((UT_hash_handle*)((char*)((delptr)->hh.prev) + \ 213 | (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ 214 | } else { \ 215 | DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ 216 | } \ 217 | if (_hd_hh_del->next) { \ 218 | ((UT_hash_handle*)((char*)_hd_hh_del->next + \ 219 | (head)->hh.tbl->hho))->prev = \ 220 | _hd_hh_del->prev; \ 221 | } \ 222 | HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ 223 | HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ 224 | (head)->hh.tbl->num_items--; \ 225 | } \ 226 | HASH_FSCK(hh,head); \ 227 | } while (0) 228 | 229 | 230 | /* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ 231 | #define HASH_FIND_STR(head,findstr,out) \ 232 | HASH_FIND(hh,head,findstr,strlen(findstr),out) 233 | #define HASH_ADD_STR(head,strfield,add) \ 234 | HASH_ADD(hh,head,strfield,strlen(add->strfield),add) 235 | #define HASH_FIND_INT(head,findint,out) \ 236 | HASH_FIND(hh,head,findint,sizeof(int),out) 237 | #define HASH_ADD_INT(head,intfield,add) \ 238 | HASH_ADD(hh,head,intfield,sizeof(int),add) 239 | #define HASH_FIND_PTR(head,findptr,out) \ 240 | HASH_FIND(hh,head,findptr,sizeof(void *),out) 241 | #define HASH_ADD_PTR(head,ptrfield,add) \ 242 | HASH_ADD(hh,head,ptrfield,sizeof(void *),add) 243 | #define HASH_DEL(head,delptr) \ 244 | HASH_DELETE(hh,head,delptr) 245 | 246 | /* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. 247 | * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. 248 | */ 249 | #ifdef HASH_DEBUG 250 | #define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) 251 | #define HASH_FSCK(hh,head) \ 252 | do { \ 253 | unsigned _bkt_i; \ 254 | unsigned _count, _bkt_count; \ 255 | char *_prev; \ 256 | struct UT_hash_handle *_thh; \ 257 | if (head) { \ 258 | _count = 0; \ 259 | for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ 260 | _bkt_count = 0; \ 261 | _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ 262 | _prev = NULL; \ 263 | while (_thh) { \ 264 | if (_prev != (char*)(_thh->hh_prev)) { \ 265 | HASH_OOPS("invalid hh_prev %p, actual %p\n", \ 266 | _thh->hh_prev, _prev ); \ 267 | } \ 268 | _bkt_count++; \ 269 | _prev = (char*)(_thh); \ 270 | _thh = _thh->hh_next; \ 271 | } \ 272 | _count += _bkt_count; \ 273 | if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ 274 | HASH_OOPS("invalid bucket count %d, actual %d\n", \ 275 | (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ 276 | } \ 277 | } \ 278 | if (_count != (head)->hh.tbl->num_items) { \ 279 | HASH_OOPS("invalid hh item count %d, actual %d\n", \ 280 | (head)->hh.tbl->num_items, _count ); \ 281 | } \ 282 | /* traverse hh in app order; check next/prev integrity, count */ \ 283 | _count = 0; \ 284 | _prev = NULL; \ 285 | _thh = &(head)->hh; \ 286 | while (_thh) { \ 287 | _count++; \ 288 | if (_prev !=(char*)(_thh->prev)) { \ 289 | HASH_OOPS("invalid prev %p, actual %p\n", \ 290 | _thh->prev, _prev ); \ 291 | } \ 292 | _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ 293 | _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ 294 | (head)->hh.tbl->hho) : NULL ); \ 295 | } \ 296 | if (_count != (head)->hh.tbl->num_items) { \ 297 | HASH_OOPS("invalid app item count %d, actual %d\n", \ 298 | (head)->hh.tbl->num_items, _count ); \ 299 | } \ 300 | } \ 301 | } while (0) 302 | #else 303 | #define HASH_FSCK(hh,head) 304 | #endif 305 | 306 | /* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to 307 | * the descriptor to which this macro is defined for tuning the hash function. 308 | * The app can #include to get the prototype for write(2). */ 309 | #ifdef HASH_EMIT_KEYS 310 | #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ 311 | do { \ 312 | unsigned _klen = fieldlen; \ 313 | write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ 314 | write(HASH_EMIT_KEYS, keyptr, fieldlen); \ 315 | } while (0) 316 | #else 317 | #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) 318 | #endif 319 | 320 | /* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ 321 | #ifdef HASH_FUNCTION 322 | #define HASH_FCN HASH_FUNCTION 323 | #else 324 | #define HASH_FCN HASH_JEN 325 | #endif 326 | 327 | /* The Bernstein hash function, used in Perl prior to v5.6 */ 328 | #define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ 329 | do { \ 330 | unsigned _hb_keylen=keylen; \ 331 | char *_hb_key=(char*)(key); \ 332 | (hashv) = 0; \ 333 | while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \ 334 | bkt = (hashv) & (num_bkts-1); \ 335 | } while (0) 336 | 337 | 338 | /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at 339 | * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ 340 | #define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ 341 | do { \ 342 | unsigned _sx_i; \ 343 | char *_hs_key=(char*)(key); \ 344 | hashv = 0; \ 345 | for(_sx_i=0; _sx_i < keylen; _sx_i++) \ 346 | hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ 347 | bkt = hashv & (num_bkts-1); \ 348 | } while (0) 349 | 350 | #define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ 351 | do { \ 352 | unsigned _fn_i; \ 353 | char *_hf_key=(char*)(key); \ 354 | hashv = 2166136261UL; \ 355 | for(_fn_i=0; _fn_i < keylen; _fn_i++) \ 356 | hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \ 357 | bkt = hashv & (num_bkts-1); \ 358 | } while(0); 359 | 360 | #define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ 361 | do { \ 362 | unsigned _ho_i; \ 363 | char *_ho_key=(char*)(key); \ 364 | hashv = 0; \ 365 | for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ 366 | hashv += _ho_key[_ho_i]; \ 367 | hashv += (hashv << 10); \ 368 | hashv ^= (hashv >> 6); \ 369 | } \ 370 | hashv += (hashv << 3); \ 371 | hashv ^= (hashv >> 11); \ 372 | hashv += (hashv << 15); \ 373 | bkt = hashv & (num_bkts-1); \ 374 | } while(0) 375 | 376 | #define HASH_JEN_MIX(a,b,c) \ 377 | do { \ 378 | a -= b; a -= c; a ^= ( c >> 13 ); \ 379 | b -= c; b -= a; b ^= ( a << 8 ); \ 380 | c -= a; c -= b; c ^= ( b >> 13 ); \ 381 | a -= b; a -= c; a ^= ( c >> 12 ); \ 382 | b -= c; b -= a; b ^= ( a << 16 ); \ 383 | c -= a; c -= b; c ^= ( b >> 5 ); \ 384 | a -= b; a -= c; a ^= ( c >> 3 ); \ 385 | b -= c; b -= a; b ^= ( a << 10 ); \ 386 | c -= a; c -= b; c ^= ( b >> 15 ); \ 387 | } while (0) 388 | 389 | #define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ 390 | do { \ 391 | unsigned _hj_i,_hj_j,_hj_k; \ 392 | char *_hj_key=(char*)(key); \ 393 | hashv = 0xfeedbeef; \ 394 | _hj_i = _hj_j = 0x9e3779b9; \ 395 | _hj_k = keylen; \ 396 | while (_hj_k >= 12) { \ 397 | _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ 398 | + ( (unsigned)_hj_key[2] << 16 ) \ 399 | + ( (unsigned)_hj_key[3] << 24 ) ); \ 400 | _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ 401 | + ( (unsigned)_hj_key[6] << 16 ) \ 402 | + ( (unsigned)_hj_key[7] << 24 ) ); \ 403 | hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ 404 | + ( (unsigned)_hj_key[10] << 16 ) \ 405 | + ( (unsigned)_hj_key[11] << 24 ) ); \ 406 | \ 407 | HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ 408 | \ 409 | _hj_key += 12; \ 410 | _hj_k -= 12; \ 411 | } \ 412 | hashv += keylen; \ 413 | switch ( _hj_k ) { \ 414 | case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ 415 | case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ 416 | case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ 417 | case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ 418 | case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ 419 | case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ 420 | case 5: _hj_j += _hj_key[4]; \ 421 | case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ 422 | case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ 423 | case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ 424 | case 1: _hj_i += _hj_key[0]; \ 425 | } \ 426 | HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ 427 | bkt = hashv & (num_bkts-1); \ 428 | } while(0) 429 | 430 | /* The Paul Hsieh hash function */ 431 | #undef get16bits 432 | #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ 433 | || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) 434 | #define get16bits(d) (*((const uint16_t *) (d))) 435 | #endif 436 | 437 | #if !defined (get16bits) 438 | #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ 439 | +(uint32_t)(((const uint8_t *)(d))[0]) ) 440 | #endif 441 | #define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ 442 | do { \ 443 | char *_sfh_key=(char*)(key); \ 444 | uint32_t _sfh_tmp, _sfh_len = keylen; \ 445 | \ 446 | int _sfh_rem = _sfh_len & 3; \ 447 | _sfh_len >>= 2; \ 448 | hashv = 0xcafebabe; \ 449 | \ 450 | /* Main loop */ \ 451 | for (;_sfh_len > 0; _sfh_len--) { \ 452 | hashv += get16bits (_sfh_key); \ 453 | _sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \ 454 | hashv = (hashv << 16) ^ _sfh_tmp; \ 455 | _sfh_key += 2*sizeof (uint16_t); \ 456 | hashv += hashv >> 11; \ 457 | } \ 458 | \ 459 | /* Handle end cases */ \ 460 | switch (_sfh_rem) { \ 461 | case 3: hashv += get16bits (_sfh_key); \ 462 | hashv ^= hashv << 16; \ 463 | hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \ 464 | hashv += hashv >> 11; \ 465 | break; \ 466 | case 2: hashv += get16bits (_sfh_key); \ 467 | hashv ^= hashv << 11; \ 468 | hashv += hashv >> 17; \ 469 | break; \ 470 | case 1: hashv += *_sfh_key; \ 471 | hashv ^= hashv << 10; \ 472 | hashv += hashv >> 1; \ 473 | } \ 474 | \ 475 | /* Force "avalanching" of final 127 bits */ \ 476 | hashv ^= hashv << 3; \ 477 | hashv += hashv >> 5; \ 478 | hashv ^= hashv << 4; \ 479 | hashv += hashv >> 17; \ 480 | hashv ^= hashv << 25; \ 481 | hashv += hashv >> 6; \ 482 | bkt = hashv & (num_bkts-1); \ 483 | } while(0); 484 | 485 | #ifdef HASH_USING_NO_STRICT_ALIASING 486 | /* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. 487 | * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. 488 | * MurmurHash uses the faster approach only on CPU's where we know it's safe. 489 | * 490 | * Note the preprocessor built-in defines can be emitted using: 491 | * 492 | * gcc -m64 -dM -E - < /dev/null (on gcc) 493 | * cc -## a.c (where a.c is a simple test file) (Sun Studio) 494 | */ 495 | #if (defined(__i386__) || defined(__x86_64__)) 496 | #define MUR_GETBLOCK(p,i) p[i] 497 | #else /* non intel */ 498 | #define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0) 499 | #define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1) 500 | #define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2) 501 | #define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3) 502 | #define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) 503 | #if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) 504 | #define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) 505 | #define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) 506 | #define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) 507 | #else /* assume little endian non-intel */ 508 | #define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) 509 | #define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) 510 | #define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) 511 | #endif 512 | #define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ 513 | (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ 514 | (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ 515 | MUR_ONE_THREE(p)))) 516 | #endif 517 | #define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) 518 | #define MUR_FMIX(_h) \ 519 | do { \ 520 | _h ^= _h >> 16; \ 521 | _h *= 0x85ebca6b; \ 522 | _h ^= _h >> 13; \ 523 | _h *= 0xc2b2ae35l; \ 524 | _h ^= _h >> 16; \ 525 | } while(0) 526 | 527 | #define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \ 528 | do { \ 529 | const uint8_t *_mur_data = (const uint8_t*)(key); \ 530 | const int _mur_nblocks = (keylen) / 4; \ 531 | uint32_t _mur_h1 = 0xf88D5353; \ 532 | uint32_t _mur_c1 = 0xcc9e2d51; \ 533 | uint32_t _mur_c2 = 0x1b873593; \ 534 | const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \ 535 | int _mur_i; \ 536 | for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \ 537 | uint32_t _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ 538 | _mur_k1 *= _mur_c1; \ 539 | _mur_k1 = MUR_ROTL32(_mur_k1,15); \ 540 | _mur_k1 *= _mur_c2; \ 541 | \ 542 | _mur_h1 ^= _mur_k1; \ 543 | _mur_h1 = MUR_ROTL32(_mur_h1,13); \ 544 | _mur_h1 = _mur_h1*5+0xe6546b64; \ 545 | } \ 546 | const uint8_t *_mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \ 547 | uint32_t _mur_k1=0; \ 548 | switch((keylen) & 3) { \ 549 | case 3: _mur_k1 ^= _mur_tail[2] << 16; \ 550 | case 2: _mur_k1 ^= _mur_tail[1] << 8; \ 551 | case 1: _mur_k1 ^= _mur_tail[0]; \ 552 | _mur_k1 *= _mur_c1; \ 553 | _mur_k1 = MUR_ROTL32(_mur_k1,15); \ 554 | _mur_k1 *= _mur_c2; \ 555 | _mur_h1 ^= _mur_k1; \ 556 | } \ 557 | _mur_h1 ^= (keylen); \ 558 | MUR_FMIX(_mur_h1); \ 559 | hashv = _mur_h1; \ 560 | bkt = hashv & (num_bkts-1); \ 561 | } while(0) 562 | #endif /* HASH_USING_NO_STRICT_ALIASING */ 563 | 564 | /* key comparison function; return 0 if keys equal */ 565 | #define HASH_KEYCMP(a,b,len) memcmp(a,b,len) 566 | 567 | /* iterate over items in a known bucket to find desired item */ 568 | #define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ 569 | do { \ 570 | if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ 571 | else out=NULL; \ 572 | while (out) { \ 573 | if (out->hh.keylen == keylen_in) { \ 574 | if ((HASH_KEYCMP(out->hh.key,keyptr,keylen_in)) == 0) break; \ 575 | } \ 576 | if (out->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,out->hh.hh_next)); \ 577 | else out = NULL; \ 578 | } \ 579 | } while(0) 580 | 581 | /* add an item to a bucket */ 582 | #define HASH_ADD_TO_BKT(head,addhh) \ 583 | do { \ 584 | head.count++; \ 585 | (addhh)->hh_next = head.hh_head; \ 586 | (addhh)->hh_prev = NULL; \ 587 | if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ 588 | (head).hh_head=addhh; \ 589 | if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ 590 | && (addhh)->tbl->noexpand != 1) { \ 591 | HASH_EXPAND_BUCKETS((addhh)->tbl); \ 592 | } \ 593 | } while(0) 594 | 595 | /* remove an item from a given bucket */ 596 | #define HASH_DEL_IN_BKT(hh,head,hh_del) \ 597 | (head).count--; \ 598 | if ((head).hh_head == hh_del) { \ 599 | (head).hh_head = hh_del->hh_next; \ 600 | } \ 601 | if (hh_del->hh_prev) { \ 602 | hh_del->hh_prev->hh_next = hh_del->hh_next; \ 603 | } \ 604 | if (hh_del->hh_next) { \ 605 | hh_del->hh_next->hh_prev = hh_del->hh_prev; \ 606 | } 607 | 608 | /* Bucket expansion has the effect of doubling the number of buckets 609 | * and redistributing the items into the new buckets. Ideally the 610 | * items will distribute more or less evenly into the new buckets 611 | * (the extent to which this is true is a measure of the quality of 612 | * the hash function as it applies to the key domain). 613 | * 614 | * With the items distributed into more buckets, the chain length 615 | * (item count) in each bucket is reduced. Thus by expanding buckets 616 | * the hash keeps a bound on the chain length. This bounded chain 617 | * length is the essence of how a hash provides constant time lookup. 618 | * 619 | * The calculation of tbl->ideal_chain_maxlen below deserves some 620 | * explanation. First, keep in mind that we're calculating the ideal 621 | * maximum chain length based on the *new* (doubled) bucket count. 622 | * In fractions this is just n/b (n=number of items,b=new num buckets). 623 | * Since the ideal chain length is an integer, we want to calculate 624 | * ceil(n/b). We don't depend on floating point arithmetic in this 625 | * hash, so to calculate ceil(n/b) with integers we could write 626 | * 627 | * ceil(n/b) = (n/b) + ((n%b)?1:0) 628 | * 629 | * and in fact a previous version of this hash did just that. 630 | * But now we have improved things a bit by recognizing that b is 631 | * always a power of two. We keep its base 2 log handy (call it lb), 632 | * so now we can write this with a bit shift and logical AND: 633 | * 634 | * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) 635 | * 636 | */ 637 | #define HASH_EXPAND_BUCKETS(tbl) \ 638 | do { \ 639 | unsigned _he_bkt; \ 640 | unsigned _he_bkt_i; \ 641 | struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ 642 | UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ 643 | _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ 644 | 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ 645 | if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ 646 | memset(_he_new_buckets, 0, \ 647 | 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ 648 | tbl->ideal_chain_maxlen = \ 649 | (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ 650 | ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ 651 | tbl->nonideal_items = 0; \ 652 | for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ 653 | { \ 654 | _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ 655 | while (_he_thh) { \ 656 | _he_hh_nxt = _he_thh->hh_next; \ 657 | HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ 658 | _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ 659 | if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ 660 | tbl->nonideal_items++; \ 661 | _he_newbkt->expand_mult = _he_newbkt->count / \ 662 | tbl->ideal_chain_maxlen; \ 663 | } \ 664 | _he_thh->hh_prev = NULL; \ 665 | _he_thh->hh_next = _he_newbkt->hh_head; \ 666 | if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ 667 | _he_thh; \ 668 | _he_newbkt->hh_head = _he_thh; \ 669 | _he_thh = _he_hh_nxt; \ 670 | } \ 671 | } \ 672 | uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ 673 | tbl->num_buckets *= 2; \ 674 | tbl->log2_num_buckets++; \ 675 | tbl->buckets = _he_new_buckets; \ 676 | tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ 677 | (tbl->ineff_expands+1) : 0; \ 678 | if (tbl->ineff_expands > 1) { \ 679 | tbl->noexpand=1; \ 680 | uthash_noexpand_fyi(tbl); \ 681 | } \ 682 | uthash_expand_fyi(tbl); \ 683 | } while(0) 684 | 685 | 686 | /* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ 687 | /* Note that HASH_SORT assumes the hash handle name to be hh. 688 | * HASH_SRT was added to allow the hash handle name to be passed in. */ 689 | #define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) 690 | #define HASH_SRT(hh,head,cmpfcn) \ 691 | do { \ 692 | unsigned _hs_i; \ 693 | unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ 694 | struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ 695 | if (head) { \ 696 | _hs_insize = 1; \ 697 | _hs_looping = 1; \ 698 | _hs_list = &((head)->hh); \ 699 | while (_hs_looping) { \ 700 | _hs_p = _hs_list; \ 701 | _hs_list = NULL; \ 702 | _hs_tail = NULL; \ 703 | _hs_nmerges = 0; \ 704 | while (_hs_p) { \ 705 | _hs_nmerges++; \ 706 | _hs_q = _hs_p; \ 707 | _hs_psize = 0; \ 708 | for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ 709 | _hs_psize++; \ 710 | _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ 711 | ((void*)((char*)(_hs_q->next) + \ 712 | (head)->hh.tbl->hho)) : NULL); \ 713 | if (! (_hs_q) ) break; \ 714 | } \ 715 | _hs_qsize = _hs_insize; \ 716 | while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ 717 | if (_hs_psize == 0) { \ 718 | _hs_e = _hs_q; \ 719 | _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ 720 | ((void*)((char*)(_hs_q->next) + \ 721 | (head)->hh.tbl->hho)) : NULL); \ 722 | _hs_qsize--; \ 723 | } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ 724 | _hs_e = _hs_p; \ 725 | _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ 726 | ((void*)((char*)(_hs_p->next) + \ 727 | (head)->hh.tbl->hho)) : NULL); \ 728 | _hs_psize--; \ 729 | } else if (( \ 730 | cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ 731 | DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ 732 | ) <= 0) { \ 733 | _hs_e = _hs_p; \ 734 | _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ 735 | ((void*)((char*)(_hs_p->next) + \ 736 | (head)->hh.tbl->hho)) : NULL); \ 737 | _hs_psize--; \ 738 | } else { \ 739 | _hs_e = _hs_q; \ 740 | _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ 741 | ((void*)((char*)(_hs_q->next) + \ 742 | (head)->hh.tbl->hho)) : NULL); \ 743 | _hs_qsize--; \ 744 | } \ 745 | if ( _hs_tail ) { \ 746 | _hs_tail->next = ((_hs_e) ? \ 747 | ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ 748 | } else { \ 749 | _hs_list = _hs_e; \ 750 | } \ 751 | _hs_e->prev = ((_hs_tail) ? \ 752 | ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ 753 | _hs_tail = _hs_e; \ 754 | } \ 755 | _hs_p = _hs_q; \ 756 | } \ 757 | _hs_tail->next = NULL; \ 758 | if ( _hs_nmerges <= 1 ) { \ 759 | _hs_looping=0; \ 760 | (head)->hh.tbl->tail = _hs_tail; \ 761 | DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ 762 | } \ 763 | _hs_insize *= 2; \ 764 | } \ 765 | HASH_FSCK(hh,head); \ 766 | } \ 767 | } while (0) 768 | 769 | /* This function selects items from one hash into another hash. 770 | * The end result is that the selected items have dual presence 771 | * in both hashes. There is no copy of the items made; rather 772 | * they are added into the new hash through a secondary hash 773 | * hash handle that must be present in the structure. */ 774 | #define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ 775 | do { \ 776 | unsigned _src_bkt, _dst_bkt; \ 777 | void *_last_elt=NULL, *_elt; \ 778 | UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ 779 | ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ 780 | if (src) { \ 781 | for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ 782 | for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ 783 | _src_hh; \ 784 | _src_hh = _src_hh->hh_next) { \ 785 | _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ 786 | if (cond(_elt)) { \ 787 | _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ 788 | _dst_hh->key = _src_hh->key; \ 789 | _dst_hh->keylen = _src_hh->keylen; \ 790 | _dst_hh->hashv = _src_hh->hashv; \ 791 | _dst_hh->prev = _last_elt; \ 792 | _dst_hh->next = NULL; \ 793 | if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ 794 | if (!dst) { \ 795 | DECLTYPE_ASSIGN(dst,_elt); \ 796 | HASH_MAKE_TABLE(hh_dst,dst); \ 797 | } else { \ 798 | _dst_hh->tbl = (dst)->hh_dst.tbl; \ 799 | } \ 800 | HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ 801 | HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ 802 | (dst)->hh_dst.tbl->num_items++; \ 803 | _last_elt = _elt; \ 804 | _last_elt_hh = _dst_hh; \ 805 | } \ 806 | } \ 807 | } \ 808 | } \ 809 | HASH_FSCK(hh_dst,dst); \ 810 | } while (0) 811 | 812 | #define HASH_CLEAR(hh,head) \ 813 | do { \ 814 | if (head) { \ 815 | uthash_free((head)->hh.tbl->buckets, \ 816 | (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ 817 | HASH_BLOOM_FREE((head)->hh.tbl); \ 818 | uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ 819 | (head)=NULL; \ 820 | } \ 821 | } while(0) 822 | 823 | #ifdef NO_DECLTYPE 824 | #define HASH_ITER(hh,head,el,tmp) \ 825 | for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ 826 | el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) 827 | #else 828 | #define HASH_ITER(hh,head,el,tmp) \ 829 | for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ 830 | el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) 831 | #endif 832 | 833 | /* obtain a count of items in the hash */ 834 | #define HASH_COUNT(head) HASH_CNT(hh,head) 835 | #define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) 836 | 837 | typedef struct UT_hash_bucket { 838 | struct UT_hash_handle *hh_head; 839 | unsigned count; 840 | 841 | /* expand_mult is normally set to 0. In this situation, the max chain length 842 | * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If 843 | * the bucket's chain exceeds this length, bucket expansion is triggered). 844 | * However, setting expand_mult to a non-zero value delays bucket expansion 845 | * (that would be triggered by additions to this particular bucket) 846 | * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. 847 | * (The multiplier is simply expand_mult+1). The whole idea of this 848 | * multiplier is to reduce bucket expansions, since they are expensive, in 849 | * situations where we know that a particular bucket tends to be overused. 850 | * It is better to let its chain length grow to a longer yet-still-bounded 851 | * value, than to do an O(n) bucket expansion too often. 852 | */ 853 | unsigned expand_mult; 854 | 855 | } UT_hash_bucket; 856 | 857 | /* random signature used only to find hash tables in external analysis */ 858 | #define HASH_SIGNATURE 0xa0111fe1 859 | #define HASH_BLOOM_SIGNATURE 0xb12220f2 860 | 861 | typedef struct UT_hash_table { 862 | UT_hash_bucket *buckets; 863 | unsigned num_buckets, log2_num_buckets; 864 | unsigned num_items; 865 | struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ 866 | ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ 867 | 868 | /* in an ideal situation (all buckets used equally), no bucket would have 869 | * more than ceil(#items/#buckets) items. that's the ideal chain length. */ 870 | unsigned ideal_chain_maxlen; 871 | 872 | /* nonideal_items is the number of items in the hash whose chain position 873 | * exceeds the ideal chain maxlen. these items pay the penalty for an uneven 874 | * hash distribution; reaching them in a chain traversal takes >ideal steps */ 875 | unsigned nonideal_items; 876 | 877 | /* ineffective expands occur when a bucket doubling was performed, but 878 | * afterward, more than half the items in the hash had nonideal chain 879 | * positions. If this happens on two consecutive expansions we inhibit any 880 | * further expansion, as it's not helping; this happens when the hash 881 | * function isn't a good fit for the key domain. When expansion is inhibited 882 | * the hash will still work, albeit no longer in constant time. */ 883 | unsigned ineff_expands, noexpand; 884 | 885 | uint32_t signature; /* used only to find hash tables in external analysis */ 886 | #ifdef HASH_BLOOM 887 | uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ 888 | uint8_t *bloom_bv; 889 | char bloom_nbits; 890 | #endif 891 | 892 | } UT_hash_table; 893 | 894 | typedef struct UT_hash_handle { 895 | struct UT_hash_table *tbl; 896 | void *prev; /* prev element in app order */ 897 | void *next; /* next element in app order */ 898 | struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ 899 | struct UT_hash_handle *hh_next; /* next hh in bucket order */ 900 | void *key; /* ptr to enclosing struct's key */ 901 | unsigned keylen; /* enclosing struct's key len */ 902 | unsigned hashv; /* result of hash-fcn(key) */ 903 | } UT_hash_handle; 904 | 905 | #endif /* UTHASH_H */ 906 | --------------------------------------------------------------------------------