/* * Copyright (C) 2015, 2016 "IoT.bzh" * Author "Manuel Bachmann" * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #define CAN_DEV "can0" const struct afb_binding_interface *interface; // Initialize CAN hvac array that will be sent trough the socket char *can_hvac_components[8] = { "LeftTemperature", "RightTemperature", "Temperature", "Unknow3", "FanSpeed", "Unknow5", "Unknow6", "Unknow7" }; // Initialize CAN hvac array that will be sent trough the socket __u8 can_hvac_values[8] = { 21, 21, 21, 240, // Don't know why 240 but it was 0xF0 in the original amb hvacplugin 0, 1, // Don't know why 1 but it was 0xF0 in the original amb hvacplugin 0, // Don't know why 0 but it was 0xF0 in the original amb hvacplugin 0 // Don't know why 0 but it was 0xF0 in the original amb hvacplugin }; struct can_handler{ int socket; struct sockaddr_can txAddress; }; /***************************************************************************************/ /***************************************************************************************/ /** **/ /** **/ /** SECTION: HANDLE CAN DEVICE **/ /** **/ /** **/ /***************************************************************************************/ /***************************************************************************************/ static struct can_handler open_can_dev() { struct can_handler ch; ch.socket = -1; ch.socket = socket(PF_CAN, SOCK_RAW, CAN_RAW); printf("Socket: %i\n", ch.socket); if (ch.socket < 0) { printf("ERROR: socket could not be created\n"); } else { struct ifreq ifr; // Attemts to open a socket to CAN bus strcpy(ifr.ifr_name, CAN_DEV); if(ioctl(ch.socket, SIOCGIFINDEX, &ifr) < 0) { close(ch.socket); ch.socket = -1; printf("ERROR: ioctl failed\n"); } else { ch.txAddress.can_family = AF_CAN; ch.txAddress.can_ifindex = ifr.ifr_ifindex; // And bind it to ch.txAddress struct if (bind(ch.socket, (struct sockaddr *)&ch.txAddress, sizeof(ch.txAddress)) < 0) { close(ch.socket); ch.socket = -1; printf("ERROR: bind failed\n"); } return ch; } } printf("Error: unexpected behavior\n"); return ch; } static void close_can_dev(struct can_handler ch) { int socketId = ch.socket; if(socketId >= 0) { close(socketId); printf("Socket closed\n"); } } static void write_can(struct can_handler ch) { printf("Write to CAN bus\n"); // Hardcoded can_id and dlc (data lenght code) struct can_frame txCanFrame; txCanFrame.can_id = 0x30; txCanFrame.can_dlc = 8; if (ch.socket >= 0) { printf("Send CAN message\n"); txCanFrame.data[0] = can_hvac_values[0]; txCanFrame.data[1] = can_hvac_values[1]; txCanFrame.data[2] = (can_hvac_values[0] + can_hvac_values[1]) & 0x02; txCanFrame.data[3] = can_hvac_values[3]; txCanFrame.data[4] = can_hvac_values[4]; txCanFrame.data[5] = can_hvac_values[5]; txCanFrame.data[6] = can_hvac_values[6]; txCanFrame.data[7] = can_hvac_values[7]; sendto(ch.socket, &txCanFrame, sizeof(struct can_frame), 0, (struct sockaddr*)&ch.txAddress, sizeof(ch.txAddress)); return; } else { printf("Error: socket not initialized\n"); return; } printf("Error sending on CAN bus. Unexpected behavior"); } static __u8 read_temp_left_zone() { return can_hvac_values[0]; } static __u8 read_temp_right_zone() { return can_hvac_values[1]; } static __u8 read_fanspeed() { return can_hvac_values[4]; } /***************************************************************************************/ /***************************************************************************************/ /** **/ /** **/ /** SECTION: BINDING VERBS IMPLEMENTATION **/ /** **/ /** **/ /***************************************************************************************/ /***************************************************************************************/ /* * @brief Simple afb-daemon ping * * @param struct afb_req : an afb request structure * */ static void ping (struct afb_req request) { static int pingcount = 0; json_object *query = afb_req_json(request); afb_req_success_f(request, NULL, "Ping Binder Daemon count=%d query=%s", ++pingcount, json_object_to_json_string(query)); } /* * @brief Get fan speed HVAC system * * @param struct afb_req : an afb request structure * */ static void get_fanspeed(struct afb_req request) { json_object *ret_json; __u8 fanspeed = read_fanspeed(); ret_json = json_object_new_object(); json_object_object_add(ret_json, "FanSpeed", json_object_new_int(fanspeed)); json_object *query = afb_req_json(request); afb_req_success_f(request, ret_json, "Fan Speed:%d query=%s", fanspeed, json_object_to_json_string(query)); } /* * @brief Set fan speed to HVAC system * * @param struct afb_req : an afb request structure * */ static void set_fanspeed(struct afb_req request) { struct can_handler ch; __u8 fanspeed = *afb_req_value(request, "FanSpeed"); // Set can_hvac array with the new fan speed value can_hvac_values[4] = fanspeed; ch = open_can_dev(); write_can(ch); close_can_dev(ch); json_object *query = afb_req_json(request); afb_req_success_f(request, NULL, "Fanspeed=%d query=%s", can_hvac_values[4], json_object_to_json_string(query)); } /* * @brief Read Consign right zone temperature for HVAC system * * @param struct afb_req : an afb request structure * */ static void get_temp_right_zone(struct afb_req request) { json_object *ret_json; __u8 temp = read_temp_right_zone(); ret_json = json_object_new_object(); json_object_object_add(ret_json, "RightTemperature", json_object_new_int(temp)); json_object *query = afb_req_json(request); afb_req_success_f(request, ret_json, "Temperature right zone:%d query=%s", temp, json_object_to_json_string(query)); } /* * @brief Read Consign left zone temperature for HVAC system * * @param struct afb_req : an afb request structure * */ static void get_temp_left_zone(struct afb_req request) { json_object *ret_json; __u8 temp = read_temp_left_zone(); ret_json = json_object_new_object(); json_object_object_add(ret_json, "LeftTemperature", json_object_new_int(temp)); json_object *query = afb_req_json(request); afb_req_success_f(request, ret_json, "Temperature left zone:%d query=%s", temp, json_object_to_json_string(query)); } /* * @brief Set right zone temperature to HVAC system * * @param struct afb_req : an afb request structure * */ static void set_temp_right_zone(struct afb_req request) { struct can_handler ch; __u8 tempright = *afb_req_value(request, "RightTemperature"); // Set can_hvac array with the new fan speed value can_hvac_values[1] = tempright; ch = open_can_dev(); write_can(ch); close_can_dev(ch); json_object *query = afb_req_json(request); afb_req_success_f(request, NULL, "Ping Binder Daemon fanspeed=%d query=%s", can_hvac_values[4], json_object_to_json_string(query)); } /* * @brief Set left zone temperature to HVAC system * * @param struct afb_req : an afb request structure * */ static void set_temp_left_zone(struct afb_req request) { struct can_handler ch; __u8 templeft = *afb_req_value(request, "LeftTemperature"); // Set can_hvac array with the new fan speed value can_hvac_values[0] = templeft; ch = open_can_dev(); write_can(ch); close_can_dev(ch); json_object *query = afb_req_json(request); afb_req_success_f(request, NULL, "Ping Binder Daemon fanspeed=%d query=%s", can_hvac_values[4], json_object_to_json_string(query)); } static void set(struct afb_req request) { struct can_handler ch; const char *comp = afb_req_value(request, "component"); __u8 comp_val = *afb_req_value(request, "value"); int i; for (i=0;i<8;i++) { if(strcmp(can_hvac_components[i], comp) == 0) { can_hvac_values[i] = comp_val; break; } } ch = open_can_dev(); write_can(ch); close_can_dev(ch); json_object *query = afb_req_json(request); afb_req_success_f(request, NULL, "Set the %s=%d query=%s", can_hvac_components[i], can_hvac_values[i], json_object_to_json_string(query)); } /* * @brief Read all values * * @param struct afb_req : an afb request structure * */ static void get_all(struct afb_req request) { json_object *ret_json; ret_json = json_object_new_object(); json_object_object_add(ret_json, "LeftTemperature", json_object_new_int(read_temp_left_zone())); json_object_object_add(ret_json, "RightTemperature", json_object_new_int(read_temp_right_zone())); json_object_object_add(ret_json, "FanSpeed", json_object_new_int(read_fanspeed())); afb_req_success_f(request, ret_json, NULL); } // TODO: Have to change session management flag to AFB_SESSION_CHECK to use token auth static const struct afb_verb_desc_v1 verbs[]= { {"ping" , AFB_SESSION_NONE, ping , "Ping the binder"}, {"get_temp_left_zone" , AFB_SESSION_NONE, get_temp_left_zone , "Get the left zone temperature"}, {"get_temp_right_zone" , AFB_SESSION_NONE, get_temp_right_zone , "Get the right zone temperature"}, {"set_temp_left_zone" , AFB_SESSION_NONE, set_temp_left_zone , "Set the left zone temperature"}, {"set_temp_right_zone" , AFB_SESSION_NONE, set_temp_right_zone , "Set the right zone temperature"}, {"set_fanspeed" , AFB_SESSION_NONE, set_fanspeed , "Set fanspeed"}, {"get_fanspeed" , AFB_SESSION_NONE, get_fanspeed , "Read fan speed"}, {"get_all" , AFB_SESSION_NONE, get_all , "Read all values"}, {"set" , AFB_SESSION_NONE, set , "Set a HVAC component value"}, {NULL} }; static const struct afb_binding plugin_desc = { .type = AFB_BINDING_VERSION_1, .v1 = { .info = "hvac hybrid service", .prefix = "hvac", .verbs = verbs } }; const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) { interface = itf; return &plugin_desc; }