|
#include <stdio.h> |
|
#include <fcntl.h> |
|
#include <sys/ioctl.h> |
|
#include <unistd.h> |
|
#include <stdint.h> |
|
#include "can4linux/can4linux/can4linux.h" |
|
|
|
uint16_t can_id = 0x401; |
|
|
|
void set_baud(int fd, int baud){ |
|
command_par_t cmd; |
|
config_par_t cfg; |
|
|
|
cmd.cmd = CMD_STOP; |
|
ioctl(fd, CAN_IOCTL_COMMAND, &cmd); |
|
cfg.target = CONF_TIMING; |
|
cfg.val1 = baud; |
|
ioctl(fd, CAN_IOCTL_CONFIG, &cfg); |
|
cmd.cmd = CMD_START; |
|
ioctl(fd, CAN_IOCTL_COMMAND, &cmd); |
|
} |
|
|
|
void can_send(int fd, canmsg_t msg){ |
|
if(write(fd, &msg, 1) != 1){ |
|
printf("Failed to send can message\n"); |
|
} |
|
} |
|
|
|
void print_msg(canmsg_t msg) { |
|
|
|
printf("Received with ret=%d: %12lu.%06lu id=0x%05lX len=%d flags=0x%02x msg=", 1, msg.timestamp.tv_sec, msg.timestamp.tv_usec, msg.id, msg.length, msg.flags); |
|
for(int i=0;i<msg.length;i++){ |
|
printf("%02X ", msg.data[i]); |
|
} |
|
putchar(10); |
|
if (msg.length == 7){ |
|
uint16_t can_key = 8 * (msg.data[0] & 0xF0) + (msg.data[1] & 0x7F); |
|
uint16_t data_key = msg.data[2] == 0xfa ? ((uint16_t)msg.data[3])<<8 | msg.data[4] : msg.data[2]; |
|
uint16_t value = msg.data[2] == 0xfa ? ((uint16_t)msg.data[5])<<8 | msg.data[6] : ((uint16_t)msg.data[3])<<8 | msg.data[4]; |
|
printf("Receiver 0x%05lX, key=0x%04X, value=%d(%X) ", can_key, data_key, value, value); |
|
switch(msg.data[0] & 0xf){ |
|
case 0: |
|
printf("write"); |
|
break; |
|
case 1: |
|
printf("read"); |
|
break; |
|
case 2: |
|
printf("response"); |
|
break; |
|
case 3: |
|
printf("ack"); |
|
break; |
|
case 4: |
|
printf("write ack"); |
|
break; |
|
case 5: |
|
printf("write respond"); |
|
break; |
|
case 6: |
|
printf("system"); |
|
break; |
|
case 7: |
|
printf("system respond"); |
|
break; |
|
} |
|
if (msg.data[1] == 0x79) { |
|
printf(" broadcast"); |
|
} |
|
putchar(10); |
|
} |
|
} |
|
|
|
int main(int argc, char *argv[]) { |
|
int fd,n; |
|
canmsg_t msg; |
|
unsigned int last_ts = 0, last_val_ts = 0; |
|
|
|
fd = open("/dev/can0", O_RDWR); |
|
if (fd < 0) { |
|
perror("open\n"); |
|
return -1; |
|
} |
|
printf("Opened fd=%d\n", fd); |
|
|
|
printf("set baudrate to %d Kbit/s\n", 20); |
|
set_baud(fd, 20); |
|
|
|
while ((n = read(fd, &msg, 1)) >= 0) { |
|
if (msg.length == 7) { |
|
uint16_t can_key = 8 * (msg.data[0] & 0xF0) + (msg.data[1] & 0x7F); |
|
uint16_t data_key = msg.data[2] == 0xfa ? ((uint16_t)msg.data[3])<<8 | msg.data[4] : msg.data[2]; |
|
uint16_t value = msg.data[2] == 0xfa ? ((uint16_t)msg.data[5])<<8 | msg.data[6] : ((uint16_t)msg.data[3])<<8 | msg.data[4]; |
|
//broadcast for us or specifically at our id |
|
if ((msg.data[1] == 0x79 && (8*(msg.data[0] & 0xF0)) == can_id & 0x780) || can_key == can_id) { |
|
if (((msg.data[0] & 0xf) == 0x6) && data_key == 0xfe && value == 0x100) { |
|
canmsg_t reply; |
|
reply.id = can_id; |
|
reply.length = 0x7; |
|
reply.data[0] = ((msg.id >> 3) & 0xf0) | 0x7; |
|
reply.data[1] = (msg.id & 0xFF); |
|
reply.data[2] = 0xfe; |
|
reply.data[3] = 0x01; |
|
reply.data[4] = 0; |
|
reply.data[5] = 0; |
|
reply.data[6] = 0; |
|
can_send(fd, reply); |
|
printf("Send broadcast response to %x\n", msg.id); |
|
print_msg(msg); |
|
} |
|
// implemented here as it seems to be needed for some wpm, but not needed for WPM4 |
|
else if((msg.data[0] & 0xf) == 0x1 && data_key == 0x5){ //raumsoll |
|
canmsg_t reply; |
|
reply.id = can_id; |
|
reply.length = 0x7; |
|
reply.data[0] = ((msg.id >> 3) & 0xf0) | 0x2; |
|
reply.data[1] = (msg.id & 0xFF); |
|
reply.data[2] = 0xfa; |
|
reply.data[3] = 0; |
|
reply.data[4] = 0x05; |
|
reply.data[5] = 0; |
|
reply.data[6] = 0xdc; //22°C |
|
can_send(fd, reply); |
|
printf("Send raumsoll response\n"); |
|
print_msg(msg); |
|
} |
|
// implemented here as it seems to be needed for some wpm, but not needed for WPM4 |
|
else if((msg.data[0] & 0xf) == 0x1 && data_key == 0x8){ //raumsoll nacht |
|
canmsg_t reply; |
|
reply.id = can_id; |
|
reply.length = 0x7; |
|
reply.data[0] = ((msg.id >> 3) & 0xf0) | 0x2; |
|
reply.data[1] = (msg.id & 0xFF); |
|
reply.data[2] = 0xfa; |
|
reply.data[3] = 0; |
|
reply.data[4] = 0x08; |
|
reply.data[5] = 0; |
|
reply.data[6] = 0xc8; //20°C |
|
can_send(fd, reply); |
|
printf("Send raumsoll nacht response\n"); |
|
print_msg(msg); |
|
} |
|
// implemented here as it seems to be needed for some wpm, but not needed for WPM4 |
|
else if((msg.data[0] & 0xf == 0x1) && data_key == 0x11){ //raumist |
|
canmsg_t reply; |
|
reply.id = can_id; |
|
reply.length = 0x7; |
|
reply.data[0] = ((msg.id >> 3) & 0xf0) | 0x2; |
|
reply.data[1] = (msg.id & 0xFF); |
|
reply.data[2] = 0xfa; |
|
reply.data[3] = 0; |
|
reply.data[4] = 0x11; |
|
reply.data[5] = 0; |
|
reply.data[6] = 0xc7; //19.9°C |
|
can_send(fd, reply); |
|
printf("Send raumist response\n"); |
|
print_msg(msg); |
|
} |
|
else if((msg.data[0] & 0xf) == 0x1 && data_key == 0x199){ //softwarenummer |
|
canmsg_t reply; |
|
reply.id = can_id; |
|
reply.length = 0x7; |
|
reply.data[0] = ((msg.id >> 3) & 0xf0) | 0x2; |
|
reply.data[1] = (msg.id & 0xFF); |
|
reply.data[2] = 0xfa; |
|
reply.data[3] = 0x01; |
|
reply.data[4] = 0x99; |
|
reply.data[5] = 0x01; |
|
reply.data[6] = 0xa0; //41.6 |
|
can_send(fd, reply); |
|
printf("Send nummer response\n"); |
|
print_msg(msg); |
|
} |
|
else if(((msg.data[0] & 0xf) == 0x1) && data_key == 0x19a){ //softwareversion |
|
canmsg_t reply; |
|
reply.id = can_id; |
|
reply.length = 0x7; |
|
reply.data[0] = ((msg.id >> 3) & 0xf0) | 0x2; |
|
reply.data[1] = (msg.id & 0xFF); |
|
reply.data[2] = 0xfa; |
|
reply.data[3] = 0x01; |
|
reply.data[4] = 0x9a; |
|
reply.data[5] = 0x0; |
|
reply.data[6] = 0x03; //0.3 |
|
can_send(fd, reply); |
|
printf("Send version response\n"); |
|
print_msg(msg); |
|
|
|
} else if (((msg.data[0] & 0xf) == 0x7) && data_key == 0xfe && value == 0x100) { // registration success |
|
printf("Got reg success\n"); |
|
print_msg(msg); |
|
} |
|
else if (((msg.data[0] & 0xf) == 0x0) && data_key == 0x4ecd){ // treat as request roomtemp |
|
printf("Got 4ecd\n"); |
|
print_msg(msg); |
|
canmsg_t s; |
|
/* //another id with roomtemp, but seems to be not used by WPM4 |
|
s.id = can_id; |
|
s.length = 0x7; |
|
s.data[0] = ((0x601 >> 3) & 0xf0); |
|
s.data[1] = (0x601 & 0xFF); |
|
s.data[2] = 0xfa; // write raumist |
|
s.data[3] = 0x4e; |
|
s.data[4] = 0x63; |
|
s.data[5] = 0x0; |
|
s.data[6] = 0xc5; // 19.7 |
|
can_send(fd, s); |
|
printf("set raumtemp to 19.7\n"); |
|
*/ |
|
s.id = can_id; |
|
s.length = 0x7; |
|
s.data[0] = ((0x601 >> 3) & 0xf0); |
|
s.data[1] = (0x601 & 0xFF); |
|
s.data[2] = 0xfa; // write raumist |
|
s.data[3] = 0x4e; |
|
s.data[4] = 0xc7; |
|
s.data[5] = 0x0; |
|
s.data[6] = 0xc6; // 19.8 |
|
can_send(fd, s); |
|
printf("set raumtemp HK1 to 19.8\n"); |
|
|
|
s.id = can_id; |
|
s.length = 0x7; |
|
s.data[0] = ((0x601 >> 3) & 0xf0); |
|
s.data[1] = (0x601 & 0xFF); |
|
s.data[2] = 0xfa; // write raumfeuchte |
|
s.data[3] = 0x4e; |
|
s.data[4] = 0xc8; |
|
s.data[5] = 0x01; |
|
s.data[6] = 0xeb; // 49.1 |
|
can_send(fd, s); |
|
printf("set raumfeuchte HK1 to 49.1\n"); |
|
} |
|
else if ((msg.data[0] & 0xf) == 0x1){ |
|
canmsg_t reply; |
|
reply.id = can_id; |
|
reply.length = 0x7; |
|
reply.data[0] = ((msg.id >> 3) & 0xf0) | 0x2; |
|
reply.data[1] = (msg.id & 0xFF); |
|
reply.data[2] = msg.data[2]; |
|
reply.data[3] = msg.data[3]; |
|
reply.data[4] = msg.data[3]; |
|
reply.data[5] = 0x80; |
|
reply.data[6] = 0x00; //0.3 |
|
can_send(fd, reply); |
|
printf("Unknown request (%x, %x, %x) reply unknown\n", (msg.data[0] & 0xf), data_key, value); |
|
print_msg(msg); |
|
print_msg(reply); |
|
} |
|
else{ |
|
printf("Unknown %x, %x, %x\n", (msg.data[0] & 0xf), data_key, value); |
|
print_msg(msg); |
|
} |
|
} |
|
if ((last_ts + 420) < msg.timestamp.tv_sec) { |
|
last_ts = msg.timestamp.tv_sec; |
|
//register at wpm |
|
canmsg_t s; |
|
s.id = can_id; |
|
s.length = 0x7; |
|
s.data[0] = 0x96; |
|
s.data[1] = 0x00; |
|
s.data[2] = 0xfe; |
|
s.data[3] = 0x01; |
|
s.data[4] = 0x0; |
|
s.data[5] = 0x0; |
|
s.data[6] = 0x0; |
|
can_send(fd, s); |
|
printf("Send init request\n"); |
|
} |
|
if ((last_val_ts + 60) < msg.timestamp.tv_sec){ |
|
last_val_ts = msg.timestamp.tv_sec; |
|
//no periodic message needed as it seems |
|
} |
|
} |
|
} |
|
|
|
if (n < 0) { |
|
perror("Read error\n"); |
|
return 1; |
|
} |
|
|
|
close(fd); |
|
|
|
return 0; |
|
} |