Fix reverse fan speed issue in demo
[apps/hvac.git] / binding / hvac-demo-binding.c
index fe20880..7f859a6 100644 (file)
@@ -1,7 +1,9 @@
 /*
  * Copyright (C) 2015, 2016 "IoT.bzh"
+ * Copyright (C) 2016 Konsulko Group
  * Author "Romain Forlot"
  * Author "Jose Bolo"
+ * Author "Scott Murray <scott.murray@konsulko.com>"
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #define _GNU_SOURCE
 
 #include <string.h>
+#include <stdbool.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <net/if.h>
 #include <linux/can.h>
+#include <math.h>
 
 #include <json-c/json.h>
 
 
 #define CAN_DEV "vcan0"
 
-#define SIMULATE_HVAC
-
 static const struct afb_binding_interface *interface;
 
+/*****************************************************************************************/
+/*****************************************************************************************/
+/**                                                                                    **/
+/**                                                                                    **/
+/**       SECTION: UTILITY FUNCTIONS                                                   **/
+/**                                                                                    **/
+/**                                                                                    **/
+/*****************************************************************************************/
+/*****************************************************************************************/
+
+/*
+ * @brief Retry a function 3 times
+ *
+ * @param int function(): function that return an int wihtout any parameter
+ *
+ * @ return : 0 if ok, -1 if failed
+ *
+ */
+static int retry( int(*func)())
+{
+       int i;
+
+       for (i=0;i<4;i++)
+       {
+               if ( (*func)() >= 0)
+               {
+                       return 0;
+               }
+               usleep(100000);
+       }
+       return -1;
+}
+
+/*****************************************************************************************/
+/*****************************************************************************************/
+/**                                                                                    **/
+/**                                                                                    **/
+/**       SECTION: HANDLE CAN DEVICE                                                   **/
+/**                                                                                    **/
+/**                                                                                    **/
+/*****************************************************************************************/
+/*****************************************************************************************/
+
 // Initialize CAN hvac array that will be sent trough the socket
 static struct {
        const char *name;
@@ -49,30 +94,20 @@ static struct {
 
 struct can_handler {
        int socket;
+       bool simulation;
+       char *send_msg;
        struct sockaddr_can txAddress;
 };
 
-static struct can_handler can_handler = { .socket = -1 };
-
-/*****************************************************************************************/
-/*****************************************************************************************/
-/**                                                                                    **/
-/**                                                                                    **/
-/**       SECTION: HANDLE CAN DEVICE                                                   **/
-/**                                                                                    **/
-/**                                                                                    **/
-/*****************************************************************************************/
-/*****************************************************************************************/
+static struct can_handler can_handler = { .socket = -1, .simulation = false, .send_msg = "SENDING CAN FRAME"};
 
-static int open_can_dev()
+static int open_can_dev_helper()
 {
-#if defined(SIMULATE_HVAC)
-       DEBUG(interface, "Defining can handler socket to 0 and return");
-       can_handler.socket = 0;
-       return 0;
-#else
        struct ifreq ifr;
 
+       DEBUG(interface, "CAN Handler socket : %d", can_handler.socket);
+       close(can_handler.socket);
+
        can_handler.socket = socket(PF_CAN, SOCK_RAW, CAN_RAW);
        if (can_handler.socket < 0)
        {
@@ -104,13 +139,26 @@ static int open_can_dev()
                can_handler.socket = -1;
        }
        return -1;
-#endif
+}
+
+static int open_can_dev()
+{
+       int rc = retry(open_can_dev_helper);
+       if(rc < 0)
+       {
+               ERROR(interface, "Open of interface %s failed. Falling back to simulation mode", CAN_DEV);
+               can_handler.socket = 0;
+               can_handler.simulation = true;
+               can_handler.send_msg = "FAKE CAN FRAME";
+               rc = 0;
+       }
+       return rc;
 }
 
 // Get original get temperature function from cpp hvacplugin code
 static uint8_t to_can_temp(uint8_t value)
 {
-       int result = ((0xF0 - 0x10) / 15) * value - 16;
+       int result = ((0xF0 - 0x10) / 15) * (value - 15) + 0x10;
        if (result < 0x10)
                result = 0x10;
        if (result > 0xF0)
@@ -159,23 +207,26 @@ static int write_can()
                txCanFrame.data[6] = 0;
                txCanFrame.data[7] = 0;
 
-#if defined(SIMULATE_HVAC)
-               DEBUG(interface, "WRITING CAN: %d %d [%02x %02x %02x %02x %02x %02x %02x %02x]\n",
+               DEBUG(interface, "%s: %d %d [%02x %02x %02x %02x %02x %02x %02x %02x]\n",
+                       can_handler.send_msg,
                        txCanFrame.can_id, txCanFrame.can_dlc,
                        txCanFrame.data[0], txCanFrame.data[1], txCanFrame.data[2], txCanFrame.data[3],
                        txCanFrame.data[4], txCanFrame.data[5], txCanFrame.data[6], txCanFrame.data[7]);
-#else
-               rc = sendto(can_handler.socket, &txCanFrame, sizeof(struct can_frame), 0,
-                       (struct sockaddr*)&can_handler.txAddress, sizeof(can_handler.txAddress));
-               if (rc < 0)
+
+               if(!can_handler.simulation)
                {
-                       ERROR(interface, "Sending can frame failed");
+                       rc = sendto(can_handler.socket, &txCanFrame, sizeof(struct can_frame), 0,
+                                   (struct sockaddr*)&can_handler.txAddress, sizeof(can_handler.txAddress));
+                       if (rc < 0)
+                       {
+                               ERROR(interface, "Sending CAN frame failed.");
+                       }
                }
-#endif
        }
        else
        {
-               ERROR(interface, "socket not initialized");
+               ERROR(interface, "socket not initialized. Attempt to reopen can device socket.");
+               open_can_dev();
        }
        return rc;
 }
@@ -269,6 +320,7 @@ static void get(struct afb_req request)
 static void set(struct afb_req request)
 {
        int i, rc, x, changed;
+       double d;
        struct json_object *query, *val;
        uint8_t values[sizeof hvac_values / sizeof *hvac_values];
        uint8_t saves[sizeof hvac_values / sizeof *hvac_values];
@@ -292,15 +344,21 @@ static void set(struct afb_req request)
                DEBUG(interface, "Searching... query: %s, i: %d, comp: %s", json_object_to_json_string(query), i, hvac_values[i].name);
                if (json_object_object_get_ex(query, hvac_values[i].name, &val))
                {
-                       DEBUG(interface, "We got it. Tests if it is an int or not.");
-                       if (!json_object_is_type(val, json_type_int))
-                       {
+                       DEBUG(interface, "We got it. Tests if it is an int or double.");
+                       if (json_object_is_type(val, json_type_int)) {
+                               x = json_object_get_int(val);
+                               DEBUG(interface, "We get an int: %d",x);
+                       }
+                       else if (json_object_is_type(val, json_type_double)) {
+                               d = json_object_get_double(val);
+                               x = (int)round(d);
+                               DEBUG(interface, "We get a double: %f => %d",d,x);
+                       }
+                       else {
                                afb_req_fail_f(request, "bad-request",
-                                       "argument '%s' isn't integer", hvac_values[i].name);
+                                       "argument '%s' isn't integer or double", hvac_values[i].name);
                                return;
                        }
-                       DEBUG(interface, "We get an 'int'. Hail for the int: %d", x);
-                       x = json_object_get_int(val);
                        if (x < 0 || x > 255)
                        {
                                afb_req_fail_f(request, "bad-request",
@@ -310,9 +368,12 @@ static void set(struct afb_req request)
                        if (values[i] != x) {
                                values[i] = (uint8_t)x;
                                changed = 1;
+                               DEBUG(interface,"%s changed to %d",hvac_values[i].name,x);
                        }
                }
-               DEBUG(interface, "Not found !");
+               else {
+                       DEBUG(interface, "%s not found in query!",hvac_values[i].name);
+               }
        }
 
        /* attemps to set new values */
@@ -327,7 +388,7 @@ static void set(struct afb_req request)
                rc = write_can();
                if (rc >= 0)
                        afb_req_success(request, NULL, NULL);
-               else {
+               else if (retry(write_can)) {
                        /* restore initial values */
                        i = (int)(sizeof hvac_values / sizeof *hvac_values);
                        while (i) {