2 * Copyright 2015-2016 Max Staudt
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License 2 as published
6 * by the Free Software Foundation.
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <linux/can.h>
17 #include <linux/can/raw.h>
19 #include <sys/ioctl.h>
24 /* OSEK/VDX NM Level 0 */
29 NM_MAIN_LIMPHOME = 0x04,
32 NM_SLEEP_CANCEL = 0x00,
33 NM_SLEEP_REQUEST = 0x10,
38 typedef unsigned char NM_ID;
39 typedef unsigned char NM_State;
48 struct NM_Node *nodes;
54 static void can_tx(int socket, struct can_frame *frame)
58 ret = write(socket, frame, sizeof(*frame));
59 if (ret != sizeof(*frame)) {
60 perror("write to CAN socket");
67 static char* nm_main_to_string(NM_State state)
69 switch(state & NM_MAIN_MASK) {
76 case NM_MAIN_LIMPHOME:
83 static char* nm_sleep_to_string(NM_State state)
85 switch(state & NM_SLEEP_MASK) {
88 case NM_SLEEP_REQUEST:
91 return "Acknowledged";
99 static void nm_dump_all(struct NM_Main *nm)
104 printf("Current system state:\n");
107 for (id = 0; id < nm->max_nodes; id++) {
108 struct NM_Node *node = &nm->nodes[id];
110 if (node->state & NM_MAIN_MASK) {
111 printf("Active node %02x:\n", id);
112 printf(" Next: %02x\n", node->next);
113 printf(" Main: %s\n", nm_main_to_string(node->state));
114 printf(" Sleep: %s\n", nm_sleep_to_string(node->state));
122 static void nm_handle_can_frame(struct NM_Main *nm, struct can_frame *frame)
128 //printf("Received CAN frame from CAN ID %03x\n", frame->can_id);
130 if (frame->can_dlc < 2) {
131 printf("Skipping short frame from CAN ID %03x\n", frame->can_id);
136 if ((frame->can_id & ~0x1f) != 0x420) {
137 printf("Skipping non-NM from CAN ID %03x\n", frame->can_id);
141 printf("Received NM frame from CAN ID %03x\n", frame->can_id);
143 id = frame->can_id & 0x1f;
144 next = frame->data[0];
145 state = frame->data[1];
147 nm->nodes[id].next = next;
148 nm->nodes[id].state = state;
155 if (frame.data[0] == my_id) {
156 struct can_frame txframe = {.can_id = base_id + next_id,
158 .data = {next_id, 01, 00, 00, 00, 00, 00, 00},
160 can_tx(socket, &txframe);
164 if (ignore_counter > 0) {
169 ? frame.can_id - base_id < next_id
170 : next_id == my_id || frame.can_id - base_id < next_id) {
171 next_id = frame.can_id - base_id;
173 struct can_frame txframe = {.can_id = base_id + my_id,
175 .data = {my_id, 02, 01, 04, 00, 04, 00, 00},
177 can_tx(socket, &txframe);
188 static int net_init(char *ifname)
192 struct sockaddr_can addr;
194 struct can_filter fi;
196 s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
202 /* Convert interface name to index */
203 memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name));
204 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
205 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
206 perror("SIOCGIFINDEX");
210 /* Open the CAN interface */
211 memset(&addr, 0, sizeof(addr));
212 addr.can_family = AF_CAN;
213 addr.can_ifindex = ifr.ifr_ifindex;
214 if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
219 recv_own_msgs = 1; /* 0 = disabled (default), 1 = enabled */
220 setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
221 &recv_own_msgs, sizeof(recv_own_msgs));
223 /* Handle only 32 NM IDs at CAN base ID 0x420 */
227 setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &fi, sizeof(struct can_filter));
232 int main(int argc, char **argv)
234 struct NM_Node nodes[32] = {{0}};
235 struct NM_Main nm = {.max_nodes = 32, .nodes = nodes};
240 printf("syntax: %s IFNAME\n", argv[0]);
244 s = net_init(argv[1]);
252 if (select(s+1, &rdfs, NULL, NULL, NULL) < 0) {
257 if (FD_ISSET(s, &rdfs)) {
258 struct can_frame frame;
261 ret = read(s, &frame, sizeof(frame));
263 perror("recvfrom CAN socket");
267 nm_handle_can_frame(&nm, &frame);