Commit e4e20620726ef860d0ea0a821e0e192f8ff07987

kanoi 2013-08-07T06:51:23

Merge pull request #471 from kanoi/master BTB voltage management via the API - and set default on startup

diff --git a/API-README b/API-README
index 29964b0..b824b04 100644
--- a/API-README
+++ b/API-README
@@ -393,6 +393,20 @@ The list of requests - a (*) means it requires privileged access - and replies a
  asccount      ASCS           Count=N| <- the number of ASCs
                               Always returns 0 if ASC mining is disabled
 
+ ascset|N,opt[,val] (*)
+               none           There is no reply section just the STATUS section
+                              stating the results of setting ASC N with opt[,val]
+                              This is only available if ASC mining is enabled
+
+                              If the ASC does not support any set options, it will
+                              always return a WARN stating ascset isn't supported
+
+                              If opt=help it will return an INFO status with a
+                              help message about the options available
+
+                              The current options are:
+                               BTB opt=millivolts val=1000 to 1310 - core voltage
+
 When you enable, disable or restart a GPU, PGA or ASC, you will also get
 Thread messages in the cgminer status window
 
@@ -446,6 +460,13 @@ miner.php - an example web page to access the API
 Feature Changelog for external applications using the API:
 
 
+API V1.27 (cgminer v3.3.2)
+
+Added API commands:
+ 'ascset' - with: BTB opt=millivolts val=1000 to 1310 - core voltage
+
+----------
+
 API V1.26 (cgminer v3.2.3)
 
 Remove all CPU support (cgminer v3.0.0)
diff --git a/api.c b/api.c
index 5d24771..8c2d995 100644
--- a/api.c
+++ b/api.c
@@ -134,7 +134,7 @@ static const char SEPARATOR = '|';
 #define SEPSTR "|"
 static const char GPUSEP = ',';
 
-static const char *APIVERSION = "1.26";
+static const char *APIVERSION = "1.27";
 static const char *DEAD = "Dead";
 #if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA) || defined(HAVE_AN_ASIC)
 static const char *SICK = "Sick";
@@ -413,6 +413,14 @@ static const char *JSON_PARAMETER = "parameter";
 #endif
 #define MSG_ASCUSBNODEV 115
 
+#ifdef HAVE_AN_ASIC
+#define MSG_MISASCOPT 116
+#define MSG_ASCNOSET 117
+#define MSG_ASCHELP 118
+#define MSG_ASCSETOK 119
+#define MSG_ASCSETERR 120
+#endif
+
 enum code_severity {
 	SEVERITY_ERR,
 	SEVERITY_WARN,
@@ -608,6 +616,11 @@ struct CODES {
  { SEVERITY_ERR,   MSG_ASCUNW,	PARAM_ASC,	"ASC %d is not flagged WELL, cannot enable" },
  { SEVERITY_SUCC,  MSG_ASCIDENT,PARAM_ASC,	"Identify command sent to ASC%d" },
  { SEVERITY_WARN,  MSG_ASCNOID,	PARAM_ASC,	"ASC%d does not support identify" },
+ { SEVERITY_ERR,   MSG_MISASCOPT, PARAM_NONE,	"Missing option after ASC number" },
+ { SEVERITY_WARN,  MSG_ASCNOSET, PARAM_ASC,	"ASC %d does not support pgaset" },
+ { SEVERITY_INFO,  MSG_ASCHELP, PARAM_BOTH,	"ASC %d set help: %s" },
+ { SEVERITY_SUCC,  MSG_ASCSETOK, PARAM_BOTH,	"ASC %d set OK" },
+ { SEVERITY_ERR,   MSG_ASCSETERR, PARAM_BOTH,	"ASC %d set failed: %s" },
 #endif
  { SEVERITY_FAIL, 0, 0, NULL }
 };
@@ -3681,6 +3694,66 @@ static void asccount(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __may
 		io_close(io_data);
 }
 
+#ifdef HAVE_AN_ASIC
+static void ascset(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
+{
+	struct cgpu_info *cgpu;
+	struct device_drv *drv;
+	char buf[TMPBUFSIZ];
+	int numasc = numascs();
+
+	if (numasc == 0) {
+		message(io_data, MSG_ASCNON, 0, NULL, isjson);
+		return;
+	}
+
+	if (param == NULL || *param == '\0') {
+		message(io_data, MSG_MISID, 0, NULL, isjson);
+		return;
+	}
+
+	char *opt = strchr(param, ',');
+	if (opt)
+		*(opt++) = '\0';
+	if (!opt || !*opt) {
+		message(io_data, MSG_MISASCOPT, 0, NULL, isjson);
+		return;
+	}
+
+	int id = atoi(param);
+	if (id < 0 || id >= numasc) {
+		message(io_data, MSG_INVASC, id, NULL, isjson);
+		return;
+	}
+
+	int dev = ascdevice(id);
+	if (dev < 0) { // Should never happen
+		message(io_data, MSG_INVASC, id, NULL, isjson);
+		return;
+	}
+
+	cgpu = get_devices(dev);
+	drv = cgpu->drv;
+
+	char *set = strchr(opt, ',');
+	if (set)
+		*(set++) = '\0';
+
+	if (!drv->set_device)
+		message(io_data, MSG_ASCNOSET, id, NULL, isjson);
+	else {
+		char *ret = drv->set_device(cgpu, opt, set, buf);
+		if (ret) {
+			if (strcasecmp(opt, "help") == 0)
+				message(io_data, MSG_ASCHELP, id, ret, isjson);
+			else
+				message(io_data, MSG_ASCSETERR, id, ret, isjson);
+		} else
+			message(io_data, MSG_ASCSETOK, id, NULL, isjson);
+	}
+}
+#endif
+
 static void checkcommand(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, char group);
 
 struct CMDS {
@@ -3743,6 +3816,7 @@ struct CMDS {
 	{ "ascenable",		ascenable,	true },
 	{ "ascdisable",		ascdisable,	true },
 	{ "ascidentify",	ascidentify,	true },
+	{ "ascset",		ascset,		true },
 #endif
 	{ "asccount",		asccount,	false },
 	{ NULL,			NULL,		false }
diff --git a/driver-avalon.c b/driver-avalon.c
index 59bd058..139c405 100644
--- a/driver-avalon.c
+++ b/driver-avalon.c
@@ -602,7 +602,7 @@ static void avalon_initialise(struct cgpu_info *avalon)
 		avalon->drv->name, avalon->device_id, err);
 }
 
-static void bitburner_set_core_voltage(struct cgpu_info *avalon, int core_voltage)
+static bool bitburner_set_core_voltage(struct cgpu_info *avalon, int core_voltage)
 {
 	uint8_t buf[2];
 	int err;
@@ -616,12 +616,15 @@ static void bitburner_set_core_voltage(struct cgpu_info *avalon, int core_voltag
 		if (unlikely(err < 0)) {
 			applog(LOG_ERR, "%s%i: SetCoreVoltage failed: err = %d",
 				avalon->drv->name, avalon->device_id, err);
+			return false;
 		} else {
 			applog(LOG_WARNING, "%s%i: Core voltage set to %d millivolts",
 				avalon->drv->name, avalon->device_id,
 				core_voltage);
 		}
+		return true;
 	}
+	return false;
 }
 
 static int bitburner_get_core_voltage(struct cgpu_info *avalon)
@@ -718,9 +721,16 @@ static bool avalon_detect_one(libusb_device *dev, struct usb_find_devices *found
 	       avalon->device_path, info->miner_count, info->asic_count, info->timeout,
 	       info->frequency);
 
-	if (usb_ident(avalon) == IDENT_BTB &&
-	    opt_bitburner_core_voltage != BITBURNER_DEFAULT_CORE_VOLTAGE)
-		bitburner_set_core_voltage(avalon, opt_bitburner_core_voltage);
+	if (usb_ident(avalon) == IDENT_BTB) {
+		if (opt_bitburner_core_voltage < BITBURNER_MIN_COREMV ||
+		    opt_bitburner_core_voltage > BITBURNER_MAX_COREMV) {
+			quit(1, "Invalid bitburner-voltage %d must be %dmv - %dmv",
+				opt_bitburner_core_voltage,
+				BITBURNER_MIN_COREMV,
+				BITBURNER_MAX_COREMV);
+		} else
+			bitburner_set_core_voltage(avalon, opt_bitburner_core_voltage);
+	}
 
 	return true;
 
@@ -1362,6 +1372,46 @@ static void avalon_shutdown(struct thr_info *thr)
 	do_avalon_close(thr);
 }
 
+static char *avalon_set_device(struct cgpu_info *avalon, char *option, char *setting, char *replybuf)
+{
+	int val;
+
+	if (usb_ident(avalon) != IDENT_BTB) {
+		sprintf(replybuf, "%s has no set options", avalon->drv->name);
+		return replybuf;
+	}
+
+	if (strcasecmp(option, "help") == 0) {
+		sprintf(replybuf, "millivolts: range %d-%d",
+					BITBURNER_MIN_COREMV, BITBURNER_MAX_COREMV);
+		return replybuf;
+	}
+
+	if (strcasecmp(option, "millivolts") == 0 || strcasecmp(option, "mv") == 0) {
+		if (!setting || !*setting) {
+			sprintf(replybuf, "missing millivolts setting");
+			return replybuf;
+		}
+
+		val = atoi(setting);
+		if (val < BITBURNER_MIN_COREMV || val > BITBURNER_MAX_COREMV) {
+			sprintf(replybuf, "invalid millivolts: '%s' valid range %d-%d",
+						setting, BITBURNER_MIN_COREMV, BITBURNER_MAX_COREMV);
+			return replybuf;
+		}
+
+		if (bitburner_set_core_voltage(avalon, val))
+			return NULL;
+		else {
+			sprintf(replybuf, "Set millivolts failed");
+			return replybuf;
+		}
+	}
+
+	sprintf(replybuf, "Unknown option: %s", option);
+	return replybuf;
+}
+
 struct device_drv avalon_drv = {
 	.drv_id = DRIVER_AVALON,
 	.dname = "avalon",
@@ -1374,6 +1424,7 @@ struct device_drv avalon_drv = {
 	.flush_work = avalon_flush_work,
 	.get_api_stats = avalon_api_stats,
 	.get_statline_before = get_avalon_statline_before,
+	.set_device = avalon_set_device,
 	.reinit_device = avalon_init,
 	.thread_shutdown = avalon_shutdown,
 };
diff --git a/driver-avalon.h b/driver-avalon.h
index 4b08098..b482e21 100644
--- a/driver-avalon.h
+++ b/driver-avalon.h
@@ -34,6 +34,10 @@
 #define AVALON_TEMP_OVERHEAT 60
 
 #define BITBURNER_DEFAULT_CORE_VOLTAGE 1200 /* in millivolts */
+#define BITBURNER_MIN_COREMV 1000
+/* change here if you want to risk killing it :)  */
+#define BITBURNER_MAX_COREMV 1310
+
 
 #define AVALON_DEFAULT_TIMEOUT 0x2D
 #define AVALON_MIN_FREQUENCY 256