+/*
+ * cesend.c - simple command line tool to send CAN-frames via udp
+ * cesend is a fork of cansend from Socket-CAN project.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+
+#include <linux/can.h>
+#include <linux/can/raw.h>
+
+#define CANID_DELIM '#'
+#define DATA_SEPERATOR '.'
+
+unsigned char asc2nibble(char c) {
+
+ if ((c >= '0') && (c <= '9'))
+ return c - '0';
+
+ if ((c >= 'A') && (c <= 'F'))
+ return c - 'A' + 10;
+
+ if ((c >= 'a') && (c <= 'f'))
+ return c - 'a' + 10;
+
+ return 16; /* error */
+}
+
+int parse_canframe(char *cs, struct can_frame *cf) {
+ /* documentation see lib.h */
+
+ int i, idx, dlc, len;
+ unsigned char tmp;
+
+ len = strlen(cs);
+ //printf("'%s' len %d\n", cs, len);
+
+ memset(cf, 0, sizeof(*cf)); /* init CAN frame, e.g. DLC = 0 */
+
+ if (len < 4)
+ return 1;
+
+ if (cs[3] == CANID_DELIM) { /* 3 digits */
+
+ idx = 4;
+ for (i=0; i<3; i++){
+ if ((tmp = asc2nibble(cs[i])) > 0x0F)
+ return 1;
+ cf->can_id |= (tmp << (2-i)*4);
+ }
+
+ } else if (cs[8] == CANID_DELIM) { /* 8 digits */
+
+ idx = 9;
+ for (i=0; i<8; i++){
+ if ((tmp = asc2nibble(cs[i])) > 0x0F)
+ return 1;
+ cf->can_id |= (tmp << (7-i)*4);
+ }
+ if (!(cf->can_id & CAN_ERR_FLAG)) /* 8 digits but no errorframe? */
+ cf->can_id |= CAN_EFF_FLAG; /* then it is an extended frame */
+
+ } else
+ return 1;
+
+ if((cs[idx] == 'R') || (cs[idx] == 'r')){ /* RTR frame */
+ cf->can_id |= CAN_RTR_FLAG;
+ return 0;
+ }
+
+ for (i=0, dlc=0; i<8; i++){
+
+ if(cs[idx] == DATA_SEPERATOR) /* skip (optional) seperator */
+ idx++;
+
+ if(idx >= len) /* end of string => end of data */
+ break;
+
+ if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
+ return 1;
+ cf->data[i] = (tmp << 4);
+ if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
+ return 1;
+ cf->data[i] |= tmp;
+ dlc++;
+ }
+
+ cf->can_dlc = dlc;
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int s; /* can raw socket */
+ int nbytes;
+ struct sockaddr_in addr;
+ struct can_frame frame;
+
+ /* check command line options */
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <can_frame>.\n", argv[0]);
+ return 1;
+ }
+
+ /* parse CAN frame */
+ if (parse_canframe(argv[1], &frame)){
+ fprintf(stderr, "\nWrong CAN-frame format!\n\n");
+ fprintf(stderr, "Try: <can_id>#{R|data}\n");
+ fprintf(stderr, "can_id can have 3 (SFF) or 8 (EFF) hex chars\n");
+ fprintf(stderr, "data has 0 to 8 hex-values that can (optionally)");
+ fprintf(stderr, " be seperated by '.'\n\n");
+ fprintf(stderr, "e.g. 5A1#11.2233.44556677.88 / 123#DEADBEEF / ");
+ fprintf(stderr, "5AA# /\n 1F334455#1122334455667788 / 123#R ");
+ fprintf(stderr, "for remote transmission request.\n\n");
+ return 1;
+ }
+
+ /* open socket */
+ if(( s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0 ) {
+ perror("socket");
+ return 1;
+ }
+
+ addr.sin_family = AF_INET;
+ inet_aton( "127.0.0.1", &addr.sin_addr );
+ addr.sin_port = htons( 10501 );
+
+ /* send frame */
+ if ((nbytes = sendto(s, &frame, sizeof(frame), 0, (struct sockaddr*)&addr, sizeof(addr))) != sizeof(frame)) {
+ perror("write");
+ return 1;
+ }
+
+ close(s);
+
+ return 0;
+}
+