diff --git a/API-README b/API-README index 29964b02..df1c27a7 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 1400 - 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 1400 - 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 5d24771e..8c2d995a 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 59bd0584..139c405a 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 4b080983..b482e210 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