[PATCH skeleton v7 12/21] Add fan control algorithm

OpenBMC Patches openbmc-patches at stwcx.xyz
Mon May 9 19:30:45 AEST 2016


From: Ken <ken.sk.lai at mail.foxconn.com>

---
 Makefile                |  10 +-
 bin/Barreleye.py        |  13 +-
 bin/startup_hacks.sh    |   4 +-
 objects/fan_algorithm.c | 566 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 584 insertions(+), 9 deletions(-)
 create mode 100755 objects/fan_algorithm.c

diff --git a/Makefile b/Makefile
index 3b8a2ae..0752813 100755
--- a/Makefile
+++ b/Makefile
@@ -29,7 +29,7 @@ LIBS_info += $(shell pkg-config --libs $(DEPPKGS))
 %.o: objects/pflash/libflash/%.c
 	$(CC) -c -o obj/$@ $< $(CFLAGS) $(INCLUDES)
 
-all: setup libopenbmc_intf power_control led_controller button_power button_reset control_host host_watchdog board_vpd pcie_slot_present flash_bios flasher pflash hwmons_barreleye control_bmc i2craw info
+all: setup libopenbmc_intf power_control led_controller button_power button_reset control_host host_watchdog board_vpd pcie_slot_present flash_bios flasher pflash hwmons_barreleye control_bmc i2craw info fan_algorithm
 
 setup: 
 	mkdir -p obj lib
@@ -80,9 +80,17 @@ i2craw:  $(OBJS2) i2craw.o
 info:   info.o
 	$(CC) -o bin/$@ obj/info.o $(LDFLAGS) $(LIBS_info)
 
+fan_algorithm:   fan_algorithm.o
+	$(CC) -o bin/$@ obj/fan_algorithm.o $(LDFLAGS) $(LIBS_info)
+
 hwmons_barreleye: hwmons_barreleye.o object_mapper.o libopenbmc_intf
 	$(CC) -o bin/$@.exe obj/hwmons_barreleye.o obj/object_mapper.o  $(LDFLAGS) $(LIBS)
 
 control_bmc: control_bmc_obj.o libopenbmc_intf
 	$(CC) -o bin/$@.exe obj/control_bmc_obj.o $(LDFLAGS) $(LIBS)
 
+i2craw:  $(OBJS2) i2craw.o
+        $(CC) -o bin/$@ obj/i2craw.o $(LDFLAGS)
+
+info:   info.o
+        $(CC) -o bin/$@ obj/info.o $(LDFLAGS) $(LIBS_info)
diff --git a/bin/Barreleye.py b/bin/Barreleye.py
index 597d93b..646177f 100755
--- a/bin/Barreleye.py
+++ b/bin/Barreleye.py
@@ -48,11 +48,6 @@ ENTER_STATE_CALLBACK = {
 			'obj_name'    : '/org/openbmc/control/host0',
 			'interface_name' : 'org.openbmc.control.Host',
 		},
-		'setMax' : {
-			'bus_name'    : 'org.openbmc.control.Fans',
-			'obj_name'    : '/org/openbmc/control/fans',
-			'interface_name' : 'org.openbmc.control.Fans',
-		},
 		'setOn' : {
 			'bus_name'   : 'org.openbmc.control.led',
 			'obj_name'   : '/org/openbmc/control/led/identify',
@@ -210,12 +205,18 @@ APPS = {
 		'monitor_process' : False,
 		'process_name'    : 'discover_system_state.py',
 	},
-        'info' : {
+    'info' : {
                 'system_state'    : 'BMC_STARTING2',
                 'start_process'   : True,
                 'monitor_process' : True,
                 'process_name'    : 'info',
         },
+    'fan_algorithm' : {
+                'system_state'    : 'HOST_POWERED_ON',
+                'start_process'   : True,
+                'monitor_process' : True,
+                'process_name'    : 'fan_algorithm',
+    },
 	'bmc_control' : {
 		'system_state'    : 'BMC_STARTING',
 		'start_process'   : True,
diff --git a/bin/startup_hacks.sh b/bin/startup_hacks.sh
index cf3632a..357a4da 100755
--- a/bin/startup_hacks.sh
+++ b/bin/startup_hacks.sh
@@ -7,8 +7,8 @@ systemctl stop serial-getty at ttyS0
  i2cset -y 0x06 0x20 0x07 0x00
  
  # Turn on all fan LED to BLUE
- i2cset -y 0x06 0x20 0x03 0x55
- i2cset -y 0x06 0x20 0x02 0xaa
+ # i2cset -y 0x06 0x20 0x03 0x55
+ # i2cset -y 0x06 0x20 0x02 0xaa
 
 # Setup VUART
 VUART=/sys/devices/platform/ahb/ahb:apb/1e787000.vuart
diff --git a/objects/fan_algorithm.c b/objects/fan_algorithm.c
new file mode 100755
index 0000000..477b7cb
--- /dev/null
+++ b/objects/fan_algorithm.c
@@ -0,0 +1,566 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <systemd/sd-bus.h>
+#include "i2c-dev.h"
+#include "log.h"
+
+const char *gService = "org.openbmc.Sensors";
+const char *fanService = "org.openbmc.control.Fans";
+
+const char *gfanflagObjPath = "/org/openbmc/sensors/FanParameter/flag";
+const char *gfanCPUvaribleObjPath = "/org/openbmc/sensors/FanParameter/flag";
+const char *gfanDIMMvaribleObjPath = "/org/openbmc/sensors/FanParameter/flag";
+			
+const char *gfanpidObjPath [3] = {"/org/openbmc/sensors/FanParameter/Kp",
+							      "/org/openbmc/sensors/FanParameter/Ki",
+							      "/org/openbmc/sensors/FanParameter/Kd"};
+
+
+const char *gCPU0ObjPath [12] = {"/org/openbmc/sensors/temperature/cpu0/core0",
+								 "/org/openbmc/sensors/temperature/cpu0/core1",
+								 "/org/openbmc/sensors/temperature/cpu0/core2",
+								 "/org/openbmc/sensors/temperature/cpu0/core3",
+								 "/org/openbmc/sensors/temperature/cpu0/core4",
+								 "/org/openbmc/sensors/temperature/cpu0/core5",
+								 "/org/openbmc/sensors/temperature/cpu0/core6",
+								 "/org/openbmc/sensors/temperature/cpu0/core7",
+								 "/org/openbmc/sensors/temperature/cpu0/core8",
+								 "/org/openbmc/sensors/temperature/cpu0/core9",
+								 "/org/openbmc/sensors/temperature/cpu0/core10",
+								 "/org/openbmc/sensors/temperature/cpu0/core11"};
+								
+const char *gCPU1ObjPath [12] = {"/org/openbmc/sensors/temperature/cpu0/core0",
+								 "/org/openbmc/sensors/temperature/cpu0/core1",
+								 "/org/openbmc/sensors/temperature/cpu0/core2",
+								 "/org/openbmc/sensors/temperature/cpu0/core3",
+								 "/org/openbmc/sensors/temperature/cpu0/core4",
+								 "/org/openbmc/sensors/temperature/cpu0/core5",
+								 "/org/openbmc/sensors/temperature/cpu0/core6",
+								 "/org/openbmc/sensors/temperature/cpu0/core7",
+								 "/org/openbmc/sensors/temperature/cpu0/core8",
+								 "/org/openbmc/sensors/temperature/cpu0/core9",
+								 "/org/openbmc/sensors/temperature/cpu0/core10",
+								 "/org/openbmc/sensors/temperature/cpu0/core11"};
+
+const char *gDIMMObjPath [32] = {"/org/openbmc/sensors/temperature/dimm0",
+								 "/org/openbmc/sensors/temperature/dimm1",
+								 "/org/openbmc/sensors/temperature/dimm2",
+								 "/org/openbmc/sensors/temperature/dimm3",
+								 "/org/openbmc/sensors/temperature/dimm4",
+								 "/org/openbmc/sensors/temperature/dimm5",
+								 "/org/openbmc/sensors/temperature/dimm6",
+								 "/org/openbmc/sensors/temperature/dimm7",
+								 "/org/openbmc/sensors/temperature/dimm8",
+								 "/org/openbmc/sensors/temperature/dimm9",
+								 "/org/openbmc/sensors/temperature/dimm10",
+								 "/org/openbmc/sensors/temperature/dimm11",
+								 "/org/openbmc/sensors/temperature/dimm12",
+								 "/org/openbmc/sensors/temperature/dimm13",
+								 "/org/openbmc/sensors/temperature/dimm14",
+								 "/org/openbmc/sensors/temperature/dimm15",
+								 "/org/openbmc/sensors/temperature/dimm16",
+								 "/org/openbmc/sensors/temperature/dimm17",
+								 "/org/openbmc/sensors/temperature/dimm18",
+								 "/org/openbmc/sensors/temperature/dimm19",
+								 "/org/openbmc/sensors/temperature/dimm20",
+								 "/org/openbmc/sensors/temperature/dimm21",
+								 "/org/openbmc/sensors/temperature/dimm22",
+								 "/org/openbmc/sensors/temperature/dimm23",
+								 "/org/openbmc/sensors/temperature/dimm24",
+								 "/org/openbmc/sensors/temperature/dimm25",
+								 "/org/openbmc/sensors/temperature/dimm26",
+								 "/org/openbmc/sensors/temperature/dimm27",
+								 "/org/openbmc/sensors/temperature/dimm28",
+								 "/org/openbmc/sensors/temperature/dimm29",
+								 "/org/openbmc/sensors/temperature/dimm30",
+								 "/org/openbmc/sensors/temperature/dimm31"};
+
+
+const char *gObjPath_Ambient = "/org/openbmc/sensors/temperature/ambient";
+const char *fanObjPath [6] ={"/org/openbmc/sensors/speed/fan0",
+							 "/org/openbmc/sensors/speed/fan1",
+							 "/org/openbmc/sensors/speed/fan2",
+							 "/org/openbmc/sensors/speed/fan3",
+							 "/org/openbmc/sensors/speed/fan4",
+							 "/org/openbmc/sensors/speed/fan5"};
+
+
+
+const char *gIntPath = "org.openbmc.SensorValue";
+
+
+char *gMessage = NULL;
+sd_bus *bus = NULL;
+
+#define MAX_BYTES 255
+
+int g_use_pec = 0;
+int g_has_write = 1;
+int g_n_write = 0;
+uint8_t g_write_bytes[MAX_BYTES];
+uint8_t g_write_color_bytes[MAX_BYTES];
+
+int g_has_read = 1;
+int g_n_read = -1;
+uint8_t g_read_bytes[MAX_BYTES];
+uint8_t g_read_tmp[MAX_BYTES];
+uint8_t g_bus = -1;
+uint8_t g_slave_addr = 0xff;
+double g_Kp = 0.7;
+double g_Ki = -0.025;
+double g_Kd = 1.0;
+int g_CPUVariable = 80;
+int g_DIMMVariable = 75;
+
+int g_Sampling_N = 20;
+int intergral_i = 0;
+int Interal_CPU_Err[20]={0};
+int Interal_DIMM_Err[20]={0};
+
+int g_fanspeed = 0;
+
+
+int Openloopspeed = 0;
+int Closeloopspeed = 0;
+int Finalfanspeed = 0;
+
+static int i2c_open() {
+  int fd;
+  char fn[32];
+  int rc;
+
+  g_bus = 6;
+  snprintf(fn, sizeof(fn), "/dev/i2c-%d", g_bus);
+  fd = open(fn, O_RDWR);
+  if (fd == -1) {
+    LOG_ERR(errno, "Failed to open i2c device %s", fn);
+	close(fd);
+    return -1;
+  }
+  return fd;
+}
+
+static int SetFanLed(int fd,int color) {
+  struct i2c_rdwr_ioctl_data data;
+  struct i2c_msg msg[2];
+  int n_msg = 0;
+  int rc;
+
+  memset(&msg, 0, sizeof(msg));
+
+  g_slave_addr = 0x20;
+  g_use_pec = 0;
+  g_n_write = 2;
+
+  if(color==1) //blue light
+  {
+  g_write_bytes[0] = 0x03;
+  g_write_bytes[1] = 0x55;
+  g_write_color_bytes[0] = 0x02;
+  g_write_color_bytes[1] = 0xaa;
+  }
+    else //red light
+	{
+    g_write_bytes[0] = 0x03;
+   	g_write_bytes[1] = 0xaa;
+    g_write_color_bytes[0] = 0x02;
+    g_write_color_bytes[1] = 0x55;
+  	}
+  
+  if (1) {
+    msg[n_msg].addr = g_slave_addr;
+    msg[n_msg].flags = (g_use_pec) ? I2C_CLIENT_PEC : 0;
+    msg[n_msg].len = g_n_write;
+    msg[n_msg].buf = g_write_bytes;
+    n_msg++;
+  }
+  if (1) {
+	  msg[n_msg].addr = g_slave_addr;
+	  msg[n_msg].flags = (g_use_pec) ? I2C_CLIENT_PEC : 0;
+	  msg[n_msg].len = g_n_write;
+	  msg[n_msg].buf = g_write_color_bytes;
+	  n_msg++;
+  }
+  data.msgs = msg;
+  data.nmsgs = n_msg;
+  rc = ioctl(fd, I2C_RDWR, &data);
+  if (rc < 0) {
+    LOG_ERR(errno, "Failed to do raw io");
+	close(fd);
+    return -1;
+  }
+
+  return 0;
+}
+
+
+int CloseLoop (int cpureading,int dimmreading)
+{
+	int i,rc;
+	int flag = 0;
+	double pid [3] = {0};
+	int CPUvarible;
+	int DIMMvarible = 0;
+	
+	int CPU_PWM_speed = 0;
+	static int CPU_PID_value = 0;
+	static int CPU_tracking_error = 0; 
+	static int CPU_integral_error = 0;
+	static int CPU_differential_error = 0;
+	static int CPU_last_error = 0;
+
+	int DIMM_PWM_speed = 0;
+	static int DIMM_PID_value = 0;
+	static int DIMM_tracking_error = 0;
+	static int DIMM_integral_error = 0;
+	static int DIMM_differential_error = 0;
+	static int DIMM_last_error = 0;
+		
+//CPU closeloop
+CPU_tracking_error = cpureading - g_CPUVariable;
+Interal_CPU_Err[intergral_i]=CPU_tracking_error;
+CPU_integral_error = 0;
+for(i=0;i<g_Sampling_N;i++)
+{
+	CPU_integral_error += Interal_CPU_Err[i] ;
+}			
+
+CPU_differential_error = CPU_tracking_error - CPU_last_error;			
+CPU_PID_value = g_Kp * CPU_tracking_error +  g_Ki * CPU_integral_error + g_Kd * CPU_differential_error;
+
+CPU_PWM_speed= CPU_PID_value + g_fanspeed;
+if(CPU_PWM_speed > 100)
+{
+	CPU_PWM_speed = 100;
+}
+if(CPU_PWM_speed < 0)
+{
+	CPU_PWM_speed = 0;
+}
+
+CPU_last_error = CPU_tracking_error;
+
+
+//DIMM closeloop
+
+	DIMM_tracking_error = dimmreading - g_DIMMVariable;
+		Interal_DIMM_Err[intergral_i]=DIMM_tracking_error;
+		intergral_i++;		
+		DIMM_integral_error = 0;
+		for(i=0;i<g_Sampling_N;i++)
+		{
+			DIMM_integral_error += Interal_DIMM_Err[i] ;
+		}	
+		if(intergral_i == g_Sampling_N)
+			intergral_i = 0;
+		
+
+    	DIMM_differential_error = DIMM_tracking_error - DIMM_last_error;			
+		DIMM_PID_value = g_Kp * DIMM_tracking_error +  g_Ki * DIMM_integral_error + g_Kd * DIMM_differential_error;		
+		DIMM_PWM_speed = DIMM_PID_value + g_fanspeed;
+
+		if(DIMM_PWM_speed > 100)
+		{
+			DIMM_PWM_speed = 100;
+		}
+		if(DIMM_PWM_speed < 0)
+		{
+			DIMM_PWM_speed = 0;
+		}
+	
+		DIMM_last_error = DIMM_tracking_error;
+
+	if (DIMM_PWM_speed>CPU_PWM_speed)
+		Closeloopspeed=DIMM_PWM_speed;
+	else
+		Closeloopspeed=CPU_PWM_speed;
+
+	if(intergral_i == g_Sampling_N)
+		intergral_i = 0;
+
+
+}
+
+
+int OpenLoop (int sensorreading)
+{
+
+
+	int speed = 0;
+	float paramA= 0;
+	float paramB= 2; 
+	float paramC= 0;
+	int Low_Amb = 20;
+	int Up_Amb = 40;
+	
+    if (sensorreading >= Up_Amb)
+    {
+    	speed = 100;
+		//printf("## Ambient >=%dC, the Fan duty is %d \n",Up_Amb,speed);	
+    }
+	else if (sensorreading <= Low_Amb)
+    {
+    	speed = 40;
+		//printf("## Ambient <=%dC, the Fan duty is %d \n",Low_Amb,speed);	
+    }
+	else
+	{
+		speed = ( paramA * sensorreading * sensorreading ) + ( paramB * sensorreading ) + paramC;
+		if(speed > 100)
+		{
+			speed = 100;
+		}	
+		if(speed < 40)
+		{
+			speed = 40;
+		}
+	//	printf("The Fan duty is %d \n",speed);
+
+	}
+
+	Openloopspeed=speed;
+
+return 0;
+}
+
+
+
+
+int Fan_control_algorithm(void) {
+
+	sd_bus *bus;
+	sd_bus_slot *slot;
+	int r, Ambient_reading, rc,retry,i;
+	int CPU0_core_temperature[12];
+	int CPU1_core_temperature[12];
+	int DIMM_temperature[32];
+	int HighestCPUtemp = 0;
+	int HighestDIMMtemp = 0;
+	int CPUnocore[2];
+	int fd;
+	int FinalFanSpeed = 0;
+	int CPUtemp=0;
+	
+	r = -1;
+	while(r < 0) {
+	/* Connect to the user bus this time */
+	r = sd_bus_open_system(&bus);
+		if(r < 0){	
+			fprintf(stderr, "fan 1 Failed to connect to system bus: %s\n", strerror(-r));
+		sleep(1);
+			}
+	
+		}
+	// SD Bus error report mechanism.
+	sd_bus_error bus_error = SD_BUS_ERROR_NULL;
+	sd_bus_message *response = NULL, *m = NULL;;
+    sd_bus_error_free(&bus_error);
+    sd_bus_message_unref(response);
+
+
+while(1){
+  	fd = i2c_open();
+	CPUtemp=0;
+	for(i=0;i<12;i++){
+       sd_bus_error_free(&bus_error);
+
+        rc = sd_bus_call_method(bus,                   // On the System Bus
+                                gService,               // Service to contact
+                                gCPU0ObjPath[i],            // Object path
+                                gIntPath,              // Interface name
+                                "getValue",          // Method to be called
+                                &bus_error,                 // object to return error
+                                &response,                  // Response message on success
+                                NULL);                       // input message (string,byte)
+
+        if(rc < 0)
+        {
+            //fprintf(stderr, "gCPU0ObjPath Failed to resolve fruid to dbus: %s\n", bus_error.message);
+           // goto finish;
+           CPU0_core_temperature[i]=0;
+        }
+		else
+		{
+			rc = sd_bus_message_read(response, "v","i", &CPU0_core_temperature[i]);
+			if (rc < 0 )
+			{ 
+         	 // fprintf(stderr, "gCPU0ObjPath Failed to parse response message:[%s]\n", strerror(-rc));
+          // goto finish;
+			}
+		}
+	//printf("CPU0 core %d value=[%d] \n",i,CPU0_core_temperature[i]);
+	if(CPU0_core_temperature[i] > HighestCPUtemp )
+		{
+		HighestCPUtemp = CPU0_core_temperature[i];
+		CPUnocore[0]=0;
+		CPUnocore[1]=i;
+		}
+	CPUtemp=CPUtemp+CPU0_core_temperature[i];
+	}
+	
+	for(i=0;i<12;i++){
+       sd_bus_error_free(&bus_error);
+
+        rc = sd_bus_call_method(bus,                   // On the System Bus
+                                gService,               // Service to contact
+                                gCPU1ObjPath[i],            // Object path
+                                gIntPath,              // Interface name
+                                "getValue",          // Method to be called
+                                &bus_error,                 // object to return error
+                                &response,                  // Response message on success
+                                NULL);                       // input message (string,byte)
+
+        if(rc < 0)
+        {
+            //fprintf(stderr, "gCPU1ObjPath Failed to resolve fruid to dbus: %s\n", bus_error.message);
+			CPU1_core_temperature[i]=0;
+			//goto finish;
+        }
+		else
+		{
+		rc = sd_bus_message_read(response, "v","i", &CPU1_core_temperature[i]);
+
+		}
+
+
+		if(CPU1_core_temperature[i] > HighestCPUtemp )
+		{
+		HighestCPUtemp = CPU1_core_temperature[i];
+		CPUnocore[0]=1;
+		CPUnocore[1]=i;
+		}
+
+	}
+
+	
+	for(i=0;i<32;i++){
+       sd_bus_error_free(&bus_error);
+
+        rc = sd_bus_call_method(bus,                   // On the System Bus
+                                gService,               // Service to contact
+                                gDIMMObjPath[i],            // Object path
+                                gIntPath,              // Interface name
+                                "getValue",          // Method to be called
+                                &bus_error,                 // object to return error
+                                &response,                  // Response message on success
+                                NULL);                       // input message (string,byte)
+
+        if(rc < 0)
+        {
+  
+            DIMM_temperature[i]=0;
+        }
+		else
+		{
+		rc = sd_bus_message_read(response, "v","i", &DIMM_temperature[i]);
+
+			if (rc < 0 )
+			{ 
+         	  fprintf(stderr, "gDIMMObjPath Failed to parse response message:[%s]\n", strerror(-rc));
+      
+			}
+
+		}
+
+	if(DIMM_temperature[i] > HighestDIMMtemp )
+		HighestDIMMtemp = DIMM_temperature[i];
+	}
+	printf("Highest DIMM temperatur is value %d \n",HighestDIMMtemp);
+
+
+
+	sd_bus_error_free(&bus_error);
+     rc = sd_bus_call_method(bus,                   // On the System Bus
+                                gService,               // Service to contact
+                                gObjPath_Ambient,            // Object path
+                                gIntPath,              // Interface name
+                                "getValue",          // Method to be called
+                                &bus_error,                 // object to return error
+                                &response,                  // Response message on success
+                                NULL);                       // input message (string,byte)
+                                // NULL);                  // First argument to getObjectFromId
+                                //"BOARD_1");             // Second Argument
+
+        if(rc < 0)
+        {
+            fprintf(stderr, "fan2 Failed to resolve fruid to dbus: %s\n", bus_error.message);
+       
+        }
+
+	rc = sd_bus_message_read(response, "v","i", &Ambient_reading);
+	if (rc < 0 )
+	{ 
+           fprintf(stderr, "fan3 Failed to parse response message:[%s]\n", strerror(-rc));
+  
+	}
+
+	  if (CPUtemp==0)
+	  	{
+		HighestCPUtemp=0;
+		HighestDIMMtemp=0;
+	  	}
+
+	CloseLoop(HighestCPUtemp,HighestDIMMtemp);
+	OpenLoop(Ambient_reading);
+
+	
+
+		if(Openloopspeed>Closeloopspeed)
+		g_fanspeed=Openloopspeed;
+		else
+		g_fanspeed=Closeloopspeed;
+	
+	if(g_fanspeed>30) 
+		SetFanLed(fd,1);
+	else
+		SetFanLed(fd,2);
+
+	FinalFanSpeed=g_fanspeed*255;
+	FinalFanSpeed=FinalFanSpeed/100;
+
+	if(HighestCPUtemp==0) //OCC sensor does not enable
+	{
+	FinalFanSpeed=255;
+	}
+
+
+ 	for(i=0;i<6;i++){
+		
+		sd_bus_error_free(&bus_error);
+	rc = sd_bus_call_method(bus,				   // On the System Bus
+							   gService,			   // Service to contact
+							   fanObjPath[i],			// Object path
+							   gIntPath,			  // Interface name
+							   "setValue",			// Method to be called
+							   &bus_error,				   // object to return error
+							   &response,				   // Response message on success
+							   "i",						// input message (string,byte)
+							   FinalFanSpeed);                  // First argument
+
+	  if(rc < 0)
+        {
+            fprintf(stderr, "fanObjPath Failed to resolve fruid to dbus: %s\n", bus_error.message);
+          //  goto finish;
+        }
+
+
+ 	}
+
+	close(fd);
+	sleep(1);
+	
+
+	finish:
+		sd_bus_unref(bus);
+		sleep(1);
+}
+	return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+
+int main(int argc, char *argv[]) {
+
+	return Fan_control_algorithm();
+}
-- 
2.8.1




More information about the openbmc mailing list