Browse Source

Merge commit '8d8f4ff' into bfgminer

Conflicts:
	README
	api.c
Luke Dashjr 14 years ago
parent
commit
482b3b8820
5 changed files with 278 additions and 146 deletions
  1. 10 4
      README
  2. 151 122
      api.c
  3. 15 0
      driver-ztex.c
  4. 4 4
      miner.c
  5. 98 16
      miner.php

+ 10 - 4
README

@@ -55,6 +55,7 @@ BFGMiner specific configuration options:
 	--disable-adl           Override detection and disable building with adl
 	--disable-adl           Override detection and disable building with adl
 	--enable-bitforce       Compile support for BitForce FPGAs(default disabled)
 	--enable-bitforce       Compile support for BitForce FPGAs(default disabled)
 	--enable-icarus         Compile support for Icarus Board(default disabled)
 	--enable-icarus         Compile support for Icarus Board(default disabled)
+	--enable-ztex           Compile support for Ztex Board(default disabled)
 
 
 Basic *nix build instructions:
 Basic *nix build instructions:
 	To build with GPU mining support:
 	To build with GPU mining support:
@@ -193,7 +194,7 @@ GPU only options:
 --worksize|-w <arg> Override detected optimal worksize - one value or comma separated list
 --worksize|-w <arg> Override detected optimal worksize - one value or comma separated list
 
 
 
 
-FPGA mining boards(BitForce, Icarus) only options:
+FPGA mining boards(BitForce, Icarus, Ztex) only options:
 
 
 --scan-serial|-S <arg> Serial port to probe for FPGA mining device
 --scan-serial|-S <arg> Serial port to probe for FPGA mining device
 
 
@@ -612,7 +613,7 @@ An example request in both formats to set GPU 0 fan to 80%:
 The format of each reply (unless stated otherwise) is a STATUS section
 The format of each reply (unless stated otherwise) is a STATUS section
 followed by an optional detail section
 followed by an optional detail section
 
 
-From API verion 1.7 onwards, reply strings in JSON and Text have the
+From API version 1.7 onwards, reply strings in JSON and Text have the
 necessary escaping as required to avoid ambiguity - they didn't before 1.7
 necessary escaping as required to avoid ambiguity - they didn't before 1.7
 For JSON the 2 characters '"' and '\' are escaped with a '\' before them
 For JSON the 2 characters '"' and '\' are escaped with a '\' before them
 For Text the 4 characters '|' ',' '=' and '\' are escaped the same way
 For Text the 4 characters '|' ',' '=' and '\' are escaped the same way
@@ -647,7 +648,7 @@ The STATUS section is:
    This defaults to the BFGMiner version but is the value of --api-description
    This defaults to the BFGMiner version but is the value of --api-description
    if it was specified at runtime.
    if it was specified at runtime.
 
 
-For API version 1.7:
+For API version 1.8:
 
 
 The list of requests - a (*) means it requires privileged access - and replies are:
 The list of requests - a (*) means it requires privileged access - and replies are:
 
 
@@ -794,6 +795,11 @@ The list of requests - a (*) means it requires privileged access - and replies a
                               stating the results of the disable request
                               stating the results of the disable request
                               This is only available if PGA mining is enabled
                               This is only available if PGA mining is enabled
 
 
+ devdetails    DEVDETAILS     Each device with a list of their static details
+                              This lists all devices including those not supported
+                              by the 'devs' command
+                              e.g. DEVDETAILS=0,Name=GPU,ID=0,Driver=opencl,...|
+
 When you enable, disable or restart a GPU or PGA, you will also get Thread messages
 When you enable, disable or restart a GPU or PGA, you will also get Thread messages
 in the BFGMiner status window
 in the BFGMiner status window
 
 
@@ -1055,7 +1061,7 @@ working in the logs?
 A: http://us.php.net/manual/en/sockets.installation.php
 A: http://us.php.net/manual/en/sockets.installation.php
 
 
 Q: What is a PGA?
 Q: What is a PGA?
-A: At the moment, BFGMiner supports 2 FPGA's: Icarus and BitForce.
+A: At the moment, BFGMiner supports 3 FPGA's: Icarus, Ztex and BitForce.
 They are Field-Programmable Gate Arrays that have been programmed to do Bitcoin
 They are Field-Programmable Gate Arrays that have been programmed to do Bitcoin
 mining. Since the acronym needs to be only 3 characters, the "Field-" part has
 mining. Since the acronym needs to be only 3 characters, the "Field-" part has
 been skipped.
 been skipped.

+ 151 - 122
api.c

@@ -152,12 +152,13 @@ static SOCKETTYPE sock = INVSOCK;
 
 
 static const char *UNAVAILABLE = " - API will not be available";
 static const char *UNAVAILABLE = " - API will not be available";
 
 
-//static const char *BLANK = "";
+static const char *BLANK = "";
 static const char *COMMA = ",";
 static const char *COMMA = ",";
 static const char SEPARATOR = '|';
 static const char SEPARATOR = '|';
+#define SEPSTR "|"
 static const char GPUSEP = ',';
 static const char GPUSEP = ',';
 
 
-static const char *APIVERSION = "1.7";
+static const char *APIVERSION = "1.8";
 static const char *DEAD = "Dead";
 static const char *DEAD = "Dead";
 static const char *SICK = "Sick";
 static const char *SICK = "Sick";
 static const char *NOSTART = "NoStart";
 static const char *NOSTART = "NoStart";
@@ -180,6 +181,9 @@ static const char *DEVICECODE = ""
 #ifdef USE_ICARUS
 #ifdef USE_ICARUS
 			"ICA "
 			"ICA "
 #endif
 #endif
+#ifdef USE_ZTEX
+			"ZTX "
+#endif
 #ifdef WANT_CPUMINE
 #ifdef WANT_CPUMINE
 			"CPU "
 			"CPU "
 #endif
 #endif
@@ -212,7 +216,7 @@ static const char *OSINFO =
 #define _MINECON	"CONFIG"
 #define _MINECON	"CONFIG"
 #define _GPU		"GPU"
 #define _GPU		"GPU"
 
 
-#if defined(USE_BITFORCE) || defined(USE_ICARUS)
+#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
 #define _PGA		"PGA"
 #define _PGA		"PGA"
 #endif
 #endif
 
 
@@ -224,6 +228,7 @@ static const char *OSINFO =
 #define _PGAS		"PGAS"
 #define _PGAS		"PGAS"
 #define _CPUS		"CPUS"
 #define _CPUS		"CPUS"
 #define _NOTIFY		"NOTIFY"
 #define _NOTIFY		"NOTIFY"
+#define _DEVDETAILS	"DEVDETAILS"
 #define _BYE		"BYE"
 #define _BYE		"BYE"
 
 
 static const char ISJSON = '{';
 static const char ISJSON = '{';
@@ -242,7 +247,7 @@ static const char ISJSON = '{';
 #define JSON_MINECON	JSON1 _MINECON JSON2
 #define JSON_MINECON	JSON1 _MINECON JSON2
 #define JSON_GPU	JSON1 _GPU JSON2
 #define JSON_GPU	JSON1 _GPU JSON2
 
 
-#if defined(USE_BITFORCE) || defined(USE_ICARUS)
+#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
 #define JSON_PGA	JSON1 _PGA JSON2
 #define JSON_PGA	JSON1 _PGA JSON2
 #endif
 #endif
 
 
@@ -254,6 +259,7 @@ static const char ISJSON = '{';
 #define JSON_PGAS	JSON1 _PGAS JSON2
 #define JSON_PGAS	JSON1 _PGAS JSON2
 #define JSON_CPUS	JSON1 _CPUS JSON2
 #define JSON_CPUS	JSON1 _CPUS JSON2
 #define JSON_NOTIFY	JSON1 _NOTIFY JSON2
 #define JSON_NOTIFY	JSON1 _NOTIFY JSON2
+#define JSON_DEVDETAILS	JSON1 _DEVDETAILS JSON2
 #define JSON_BYE	JSON1 _BYE JSON1
 #define JSON_BYE	JSON1 _BYE JSON1
 #define JSON_CLOSE	JSON3
 #define JSON_CLOSE	JSON3
 #define JSON_END	JSON4
 #define JSON_END	JSON4
@@ -321,7 +327,7 @@ static const char *JSON_PARAMETER = "parameter";
 #define MSG_TOOMANYP 54
 #define MSG_TOOMANYP 54
 #define MSG_ADDPOOL 55
 #define MSG_ADDPOOL 55
 
 
-#if defined(USE_BITFORCE) || defined(USE_ICARUS)
+#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
 #define MSG_PGANON 56
 #define MSG_PGANON 56
 #define MSG_PGADEV 57
 #define MSG_PGADEV 57
 #define MSG_INVPGA 58
 #define MSG_INVPGA 58
@@ -330,7 +336,7 @@ static const char *JSON_PARAMETER = "parameter";
 #define MSG_NUMPGA 59
 #define MSG_NUMPGA 59
 #define MSG_NOTIFY 60
 #define MSG_NOTIFY 60
 
 
-#if defined(USE_BITFORCE) || defined(USE_ICARUS)
+#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
 #define MSG_PGALRENA 61
 #define MSG_PGALRENA 61
 #define MSG_PGALRDIS 62
 #define MSG_PGALRDIS 62
 #define MSG_PGAENA 63
 #define MSG_PGAENA 63
@@ -341,6 +347,7 @@ static const char *JSON_PARAMETER = "parameter";
 #define MSG_REMLASTP 66
 #define MSG_REMLASTP 66
 #define MSG_ACTPOOL 67
 #define MSG_ACTPOOL 67
 #define MSG_REMPOOL 68
 #define MSG_REMPOOL 68
+#define MSG_DEVDETAILS 69
 
 
 enum code_severity {
 enum code_severity {
 	SEVERITY_ERR,
 	SEVERITY_ERR,
@@ -386,7 +393,7 @@ struct CODES {
  { SEVERITY_ERR,   MSG_NOPOOL,	PARAM_NONE,	"No pools" },
  { SEVERITY_ERR,   MSG_NOPOOL,	PARAM_NONE,	"No pools" },
 
 
  { SEVERITY_SUCC,  MSG_DEVS,	PARAM_DMAX,	"%d GPU(s)"
  { SEVERITY_SUCC,  MSG_DEVS,	PARAM_DMAX,	"%d GPU(s)"
-#if defined(USE_BITFORCE) || defined(USE_ICARUS)
+#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
 						" - %d PGA(s)"
 						" - %d PGA(s)"
 #endif
 #endif
 #ifdef WANT_CPUMINE
 #ifdef WANT_CPUMINE
@@ -395,7 +402,7 @@ struct CODES {
  },
  },
 
 
  { SEVERITY_ERR,   MSG_NODEVS,	PARAM_NONE,	"No GPUs"
  { SEVERITY_ERR,   MSG_NODEVS,	PARAM_NONE,	"No GPUs"
-#if defined(USE_BITFORCE) || defined(USE_ICARUS)
+#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
 						"/PGAs"
 						"/PGAs"
 #endif
 #endif
 #ifdef WANT_CPUMINE
 #ifdef WANT_CPUMINE
@@ -409,7 +416,7 @@ struct CODES {
  { SEVERITY_ERR,   MSG_INVCMD,	PARAM_NONE,	"Invalid command" },
  { SEVERITY_ERR,   MSG_INVCMD,	PARAM_NONE,	"Invalid command" },
  { SEVERITY_ERR,   MSG_MISID,	PARAM_NONE,	"Missing device id parameter" },
  { SEVERITY_ERR,   MSG_MISID,	PARAM_NONE,	"Missing device id parameter" },
  { SEVERITY_SUCC,  MSG_GPUDEV,	PARAM_GPU,	"GPU%d" },
  { SEVERITY_SUCC,  MSG_GPUDEV,	PARAM_GPU,	"GPU%d" },
-#if defined(USE_BITFORCE) || defined(USE_ICARUS)
+#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
  { SEVERITY_ERR,   MSG_PGANON,	PARAM_NONE,	"No PGAs" },
  { SEVERITY_ERR,   MSG_PGANON,	PARAM_NONE,	"No PGAs" },
  { SEVERITY_SUCC,  MSG_PGADEV,	PARAM_PGA,	"PGA%d" },
  { SEVERITY_SUCC,  MSG_PGADEV,	PARAM_PGA,	"PGA%d" },
  { SEVERITY_ERR,   MSG_INVPGA,	PARAM_PGAMAX,	"Invalid PGA id %d - range is 0 - %d" },
  { SEVERITY_ERR,   MSG_INVPGA,	PARAM_PGAMAX,	"Invalid PGA id %d - range is 0 - %d" },
@@ -465,6 +472,7 @@ struct CODES {
  { SEVERITY_ERR,   MSG_ACTPOOL, PARAM_POOL,	"Cannot remove active pool %d:'%s'" },
  { SEVERITY_ERR,   MSG_ACTPOOL, PARAM_POOL,	"Cannot remove active pool %d:'%s'" },
  { SEVERITY_SUCC,  MSG_REMPOOL, PARAM_BOTH,	"Removed pool %d:'%s'" },
  { SEVERITY_SUCC,  MSG_REMPOOL, PARAM_BOTH,	"Removed pool %d:'%s'" },
  { SEVERITY_SUCC,  MSG_NOTIFY,	PARAM_NONE,	"Notify" },
  { SEVERITY_SUCC,  MSG_NOTIFY,	PARAM_NONE,	"Notify" },
+ { SEVERITY_SUCC,  MSG_DEVDETAILS,PARAM_NONE,	"Device Details" },
  { SEVERITY_FAIL, 0, 0, NULL }
  { SEVERITY_FAIL, 0, 0, NULL }
 };
 };
 
 
@@ -491,6 +499,10 @@ extern struct device_api bitforce_api;
 extern struct device_api icarus_api;
 extern struct device_api icarus_api;
 #endif
 #endif
 
 
+#ifdef USE_ZTEX
+extern struct device_api ztex_api;
+#endif
+
 // This is only called when expected to be needed (rarely)
 // This is only called when expected to be needed (rarely)
 // i.e. strings outside of the codes control (input from the user)
 // i.e. strings outside of the codes control (input from the user)
 static char *escape_string(char *str, bool isjson)
 static char *escape_string(char *str, bool isjson)
@@ -553,7 +565,7 @@ static char *escape_string(char *str, bool isjson)
 	return buf;
 	return buf;
 }
 }
 
 
-#if defined(USE_BITFORCE) || defined(USE_ICARUS)
+#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
 static int numpgas()
 static int numpgas()
 {
 {
 	int count = 0;
 	int count = 0;
@@ -567,6 +579,10 @@ static int numpgas()
 #ifdef USE_ICARUS
 #ifdef USE_ICARUS
 		if (devices[i]->api == &icarus_api)
 		if (devices[i]->api == &icarus_api)
 			count++;
 			count++;
+#endif
+#ifdef USE_ZTEX
+		if (devices[i]->api == &ztex_api)
+			count++;
 #endif
 #endif
 	}
 	}
 	return count;
 	return count;
@@ -585,6 +601,10 @@ static int pgadevice(int pgaid)
 #ifdef USE_ICARUS
 #ifdef USE_ICARUS
 		if (devices[i]->api == &icarus_api)
 		if (devices[i]->api == &icarus_api)
 			count++;
 			count++;
+#endif
+#ifdef USE_ZTEX
+		if (devices[i]->api == &ztex_api)
+			count++;
 #endif
 #endif
 		if (count == (pgaid + 1))
 		if (count == (pgaid + 1))
 			return i;
 			return i;
@@ -600,7 +620,7 @@ static char *message(int messageid, int paramid, char *param2, bool isjson)
 {
 {
 	char severity;
 	char severity;
 	char *ptr;
 	char *ptr;
-#if defined(USE_BITFORCE) || defined(USE_ICARUS)
+#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
 	int pga;
 	int pga;
 #endif
 #endif
 #ifdef WANT_CPUMINE
 #ifdef WANT_CPUMINE
@@ -626,10 +646,10 @@ static char *message(int messageid, int paramid, char *param2, bool isjson)
 				break;
 				break;
 			}
 			}
 
 
-			if (isjson)
-				sprintf(msg_buffer, JSON_START JSON_STATUS "{\"" _STATUS "\":\"%c\",\"When\":%lu,\"Code\":%d,\"Msg\":\"", severity, (unsigned long)when, messageid);
-			else
-				sprintf(msg_buffer, _STATUS "=%c,When=%lu,Code=%d,Msg=", severity, (unsigned long)when, messageid);
+			sprintf(msg_buffer, isjson
+				? JSON_START JSON_STATUS "{\"" _STATUS "\":\"%c\",\"When\":%lu,\"Code\":%d,\"Msg\":\""
+				: _STATUS "=%c,When=%lu,Code=%d,Msg=",
+				severity, (unsigned long)when, messageid);
 
 
 			ptr = msg_buffer + strlen(msg_buffer);
 			ptr = msg_buffer + strlen(msg_buffer);
 
 
@@ -645,7 +665,7 @@ static char *message(int messageid, int paramid, char *param2, bool isjson)
 			case PARAM_GPUMAX:
 			case PARAM_GPUMAX:
 				sprintf(ptr, codes[i].description, paramid, nDevs - 1);
 				sprintf(ptr, codes[i].description, paramid, nDevs - 1);
 				break;
 				break;
-#if defined(USE_BITFORCE) || defined(USE_ICARUS)
+#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
 			case PARAM_PGAMAX:
 			case PARAM_PGAMAX:
 				pga = numpgas();
 				pga = numpgas();
 				sprintf(ptr, codes[i].description, paramid, pga - 1);
 				sprintf(ptr, codes[i].description, paramid, pga - 1);
@@ -667,7 +687,7 @@ static char *message(int messageid, int paramid, char *param2, bool isjson)
 				sprintf(ptr, codes[i].description, paramid, total_pools - 1);
 				sprintf(ptr, codes[i].description, paramid, total_pools - 1);
 				break;
 				break;
 			case PARAM_DMAX:
 			case PARAM_DMAX:
-#if defined(USE_BITFORCE) || defined(USE_ICARUS)
+#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
 				pga = numpgas();
 				pga = numpgas();
 #endif
 #endif
 #ifdef WANT_CPUMINE
 #ifdef WANT_CPUMINE
@@ -678,7 +698,7 @@ static char *message(int messageid, int paramid, char *param2, bool isjson)
 #endif
 #endif
 
 
 				sprintf(ptr, codes[i].description, nDevs
 				sprintf(ptr, codes[i].description, nDevs
-#if defined(USE_BITFORCE) || defined(USE_ICARUS)
+#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
 					, pga
 					, pga
 #endif
 #endif
 #ifdef WANT_CPUMINE
 #ifdef WANT_CPUMINE
@@ -702,35 +722,30 @@ static char *message(int messageid, int paramid, char *param2, bool isjson)
 
 
 			ptr = msg_buffer + strlen(msg_buffer);
 			ptr = msg_buffer + strlen(msg_buffer);
 
 
-			if (isjson)
-				sprintf(ptr, "\",\"Description\":\"%s\"}" JSON_CLOSE, opt_api_description);
-			else
-				sprintf(ptr, ",Description=%s%c", opt_api_description, SEPARATOR);
+			sprintf(ptr, isjson
+				? "\",\"Description\":\"%s\"}" JSON_CLOSE
+				: ",Description=%s" SEPSTR,
+				opt_api_description);
 
 
 			return msg_buffer;
 			return msg_buffer;
 		}
 		}
 	}
 	}
 
 
-	if (isjson)
-		sprintf(msg_buffer, JSON_START JSON_STATUS "{\"" _STATUS "\":\"F\",\"When\":%lu,\"Code\":-1,\"Msg\":\"%d\",\"Description\":\"%s\"}" JSON_CLOSE,
-			(unsigned long)when, messageid, opt_api_description);
-	else
-		sprintf(msg_buffer, _STATUS "=F,When=%lu,Code=-1,Msg=%d,Description=%s%c",
-			(unsigned long)when, messageid, opt_api_description, SEPARATOR);
+	sprintf(msg_buffer, isjson
+		? JSON_START JSON_STATUS "{\"" _STATUS "\":\"F\",\"When\":%lu,\"Code\":-1,\"Msg\":\"%d\",\"Description\":\"%s\"}" JSON_CLOSE
+		: _STATUS "=F,When=%lu,Code=-1,Msg=%d,Description=%s" SEPSTR,
+		(unsigned long)when, messageid, opt_api_description);
 
 
 	return msg_buffer;
 	return msg_buffer;
 }
 }
 
 
 static void apiversion(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
 static void apiversion(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
 {
 {
-	if (isjson)
-		sprintf(io_buffer, "%s," JSON_VERSION "{\"CGMiner\":\"%s\",\"API\":\"%s\"}" JSON_CLOSE,
-			message(MSG_VERSION, 0, NULL, isjson),
-			VERSION, APIVERSION);
-	else
-		sprintf(io_buffer, "%s" _VERSION ",CGMiner=%s,API=%s%c",
-			message(MSG_VERSION, 0, NULL, isjson),
-			VERSION, APIVERSION, SEPARATOR);
+	sprintf(io_buffer, isjson
+		? "%s," JSON_VERSION "{\"CGMiner\":\"%s\",\"API\":\"%s\"}" JSON_CLOSE
+		: "%s" _VERSION ",CGMiner=%s,API=%s" SEPSTR,
+		message(MSG_VERSION, 0, NULL, isjson),
+		VERSION, APIVERSION);
 }
 }
 
 
 static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
 static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
@@ -753,7 +768,7 @@ static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
 	const char *adl = NO;
 	const char *adl = NO;
 #endif
 #endif
 
 
-#if defined(USE_BITFORCE) || defined(USE_ICARUS)
+#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
 	pgacount = numpgas();
 	pgacount = numpgas();
 #endif
 #endif
 
 
@@ -763,10 +778,12 @@ static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
 
 
 	strcpy(io_buffer, message(MSG_MINECON, 0, NULL, isjson));
 	strcpy(io_buffer, message(MSG_MINECON, 0, NULL, isjson));
 
 
-	if (isjson)
-		sprintf(buf, "," JSON_MINECON "{\"GPU Count\":%d,\"PGA Count\":%d,\"CPU Count\":%d,\"Pool Count\":%d,\"ADL\":\"%s\",\"ADL in use\":\"%s\",\"Strategy\":\"%s\",\"Log Interval\":%d,\"Device Code\":\"%s\",\"OS\":\"%s\"}" JSON_CLOSE, nDevs, pgacount, cpucount, total_pools, adl, adlinuse, strategies[pool_strategy].s, opt_log_interval, DEVICECODE, OSINFO);
-	else
-		sprintf(buf, _MINECON ",GPU Count=%d,PGA Count=%d,CPU Count=%d,Pool Count=%d,ADL=%s,ADL in use=%s,Strategy=%s,Log Interval=%d,Device Code=%s,OS=%s%c", nDevs, pgacount, cpucount, total_pools, adl, adlinuse, strategies[pool_strategy].s, opt_log_interval, DEVICECODE, OSINFO, SEPARATOR);
+	sprintf(buf, isjson
+		? "," JSON_MINECON "{\"GPU Count\":%d,\"PGA Count\":%d,\"CPU Count\":%d,\"Pool Count\":%d,\"ADL\":\"%s\",\"ADL in use\":\"%s\",\"Strategy\":\"%s\",\"Log Interval\":%d,\"Device Code\":\"%s\",\"OS\":\"%s\"}" JSON_CLOSE
+		: _MINECON ",GPU Count=%d,PGA Count=%d,CPU Count=%d,Pool Count=%d,ADL=%s,ADL in use=%s,Strategy=%s,Log Interval=%d,Device Code=%s,OS=%s" SEPSTR,
+
+		nDevs, pgacount, cpucount, total_pools, adl, adlinuse,
+		strategies[pool_strategy].s, opt_log_interval, DEVICECODE, OSINFO);
 
 
 	strcat(io_buffer, buf);
 	strcat(io_buffer, buf);
 }
 }
@@ -873,6 +890,7 @@ static void gpustatus(int gpu, bool isjson)
 	devstatus_an(io_buffer, &gpus[gpu], isjson);
 	devstatus_an(io_buffer, &gpus[gpu], isjson);
 }
 }
 
 
+#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
 static void pgastatus(int pga, bool isjson)
 static void pgastatus(int pga, bool isjson)
 {
 {
 	int dev = pgadevice(pga);
 	int dev = pgadevice(pga);
@@ -880,6 +898,7 @@ static void pgastatus(int pga, bool isjson)
 		return;
 		return;
 	devstatus_an(io_buffer, devices[dev], isjson);
 	devstatus_an(io_buffer, devices[dev], isjson);
 }
 }
+#endif
 
 
 __maybe_unused
 __maybe_unused
 static void cpustatus(int cpu, bool isjson)
 static void cpustatus(int cpu, bool isjson)
@@ -963,7 +982,7 @@ static void gpudev(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
 		strcat(io_buffer, JSON_CLOSE);
 		strcat(io_buffer, JSON_CLOSE);
 }
 }
 
 
-#if defined(USE_BITFORCE) || defined(USE_ICARUS)
+#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
 static void pgadev(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
 static void pgadev(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
 {
 {
 	int numpga = numpgas();
 	int numpga = numpgas();
@@ -1167,27 +1186,18 @@ static void poolstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
 		rpc_url = escape_string(pool->rpc_url, isjson);
 		rpc_url = escape_string(pool->rpc_url, isjson);
 		rpc_user = escape_string(pool->rpc_user, isjson);
 		rpc_user = escape_string(pool->rpc_user, isjson);
 
 
-		if (isjson)
-			sprintf(buf, "%s{\"POOL\":%d,\"URL\":\"%s\",\"Status\":\"%s\",\"Priority\":%d,\"Long Poll\":\"%s\",\"Getworks\":%d,\"Accepted\":%d,\"Rejected\":%d,\"Discarded\":%d,\"Stale\":%d,\"Get Failures\":%d,\"Remote Failures\":%d,\"User\":\"%s\"}",
-				(i > 0) ? COMMA : "",
-				i, rpc_url, status, pool->prio, lp,
-				pool->getwork_requested,
-				pool->accepted, pool->rejected,
-				pool->discarded_work,
-				pool->stale_shares,
-				pool->getfail_occasions,
-				pool->remotefail_occasions,
-				rpc_user);
-		else
-			sprintf(buf, "POOL=%d,URL=%s,Status=%s,Priority=%d,Long Poll=%s,Getworks=%d,Accepted=%d,Rejected=%d,Discarded=%d,Stale=%d,Get Failures=%d,Remote Failures=%d,User=%s%c",
-				i, rpc_url, status, pool->prio, lp,
-				pool->getwork_requested,
-				pool->accepted, pool->rejected,
-				pool->discarded_work,
-				pool->stale_shares,
-				pool->getfail_occasions,
-				pool->remotefail_occasions,
-				rpc_user, SEPARATOR);
+		sprintf(buf, isjson
+			? "%s{\"POOL\":%d,\"URL\":\"%s\",\"Status\":\"%s\",\"Priority\":%d,\"Long Poll\":\"%s\",\"Getworks\":%d,\"Accepted\":%d,\"Rejected\":%d,\"Discarded\":%d,\"Stale\":%d,\"Get Failures\":%d,\"Remote Failures\":%d,\"User\":\"%s\"}"
+			: "%sPOOL=%d,URL=%s,Status=%s,Priority=%d,Long Poll=%s,Getworks=%d,Accepted=%d,Rejected=%d,Discarded=%d,Stale=%d,Get Failures=%d,Remote Failures=%d,User=%s" SEPSTR,
+			(isjson && (i > 0)) ? COMMA : BLANK,
+			i, rpc_url, status, pool->prio, lp,
+			pool->getwork_requested,
+			pool->accepted, pool->rejected,
+			pool->discarded_work,
+			pool->stale_shares,
+			pool->getfail_occasions,
+			pool->remotefail_occasions,
+			rpc_user);
 
 
 		strcat(io_buffer, buf);
 		strcat(io_buffer, buf);
 
 
@@ -1218,35 +1228,23 @@ static void summary(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, boo
 	mhs = total_mhashes_done / total_secs;
 	mhs = total_mhashes_done / total_secs;
 
 
 #ifdef WANT_CPUMINE
 #ifdef WANT_CPUMINE
-	if (isjson)
-		sprintf(io_buffer, "%s," JSON_SUMMARY "{\"Elapsed\":%.0f,\"Algorithm\":\"%s\",\"MHS av\":%.2f,\"Found Blocks\":%d,\"Getworks\":%d,\"Accepted\":%d,\"Rejected\":%d,\"Hardware Errors\":%d,\"Utility\":%.2f,\"Discarded\":%d,\"Stale\":%d,\"Get Failures\":%d,\"Local Work\":%u,\"Remote Failures\":%u,\"Network Blocks\":%u,\"Total MH\":%.4f}" JSON_CLOSE,
-			message(MSG_SUMM, 0, NULL, isjson),
-			total_secs, algo, mhs, found_blocks,
-			total_getworks, total_accepted, total_rejected,
-			hw_errors, utility, total_discarded, total_stale,
-			total_go, local_work, total_ro, new_blocks, total_mhashes_done);
-	else
-		sprintf(io_buffer, "%s" _SUMMARY ",Elapsed=%.0f,Algorithm=%s,MHS av=%.2f,Found Blocks=%d,Getworks=%d,Accepted=%d,Rejected=%d,Hardware Errors=%d,Utility=%.2f,Discarded=%d,Stale=%d,Get Failures=%d,Local Work=%u,Remote Failures=%u,Network Blocks=%u,Total MH=%.4f%c",
-			message(MSG_SUMM, 0, NULL, isjson),
-			total_secs, algo, mhs, found_blocks,
-			total_getworks, total_accepted, total_rejected,
-			hw_errors, utility, total_discarded, total_stale,
-			total_go, local_work, total_ro, new_blocks, total_mhashes_done, SEPARATOR);
+	sprintf(io_buffer, isjson
+		? "%s," JSON_SUMMARY "{\"Elapsed\":%.0f,\"Algorithm\":\"%s\",\"MHS av\":%.2f,\"Found Blocks\":%d,\"Getworks\":%d,\"Accepted\":%d,\"Rejected\":%d,\"Hardware Errors\":%d,\"Utility\":%.2f,\"Discarded\":%d,\"Stale\":%d,\"Get Failures\":%d,\"Local Work\":%u,\"Remote Failures\":%u,\"Network Blocks\":%u,\"Total MH\":%.4f}" JSON_CLOSE
+		: "%s" _SUMMARY ",Elapsed=%.0f,Algorithm=%s,MHS av=%.2f,Found Blocks=%d,Getworks=%d,Accepted=%d,Rejected=%d,Hardware Errors=%d,Utility=%.2f,Discarded=%d,Stale=%d,Get Failures=%d,Local Work=%u,Remote Failures=%u,Network Blocks=%u,Total MH=%.4f" SEPSTR,
+		message(MSG_SUMM, 0, NULL, isjson),
+		total_secs, algo, mhs, found_blocks,
+		total_getworks, total_accepted, total_rejected,
+		hw_errors, utility, total_discarded, total_stale,
+		total_go, local_work, total_ro, new_blocks, total_mhashes_done);
 #else
 #else
-	if (isjson)
-		sprintf(io_buffer, "%s," JSON_SUMMARY "{\"Elapsed\":%.0f,\"MHS av\":%.2f,\"Found Blocks\":%d,\"Getworks\":%d,\"Accepted\":%d,\"Rejected\":%d,\"Hardware Errors\":%d,\"Utility\":%.2f,\"Discarded\":%d,\"Stale\":%d,\"Get Failures\":%d,\"Local Work\":%u,\"Remote Failures\":%u,\"Network Blocks\":%u,\"Total MH\":%.4f}" JSON_CLOSE,
-			message(MSG_SUMM, 0, NULL, isjson),
-			total_secs, mhs, found_blocks,
-			total_getworks, total_accepted, total_rejected,
-			hw_errors, utility, total_discarded, total_stale,
-			total_go, local_work, total_ro, new_blocks, total_mhashes_done);
-	else
-		sprintf(io_buffer, "%s" _SUMMARY ",Elapsed=%.0f,MHS av=%.2f,Found Blocks=%d,Getworks=%d,Accepted=%d,Rejected=%d,Hardware Errors=%d,Utility=%.2f,Discarded=%d,Stale=%d,Get Failures=%d,Local Work=%u,Remote Failures=%u,Network Blocks=%u,Total MH=%.4f%c",
-			message(MSG_SUMM, 0, NULL, isjson),
-			total_secs, mhs, found_blocks,
-			total_getworks, total_accepted, total_rejected,
-			hw_errors, utility, total_discarded, total_stale,
-			total_go, local_work, total_ro, new_blocks, total_mhashes_done, SEPARATOR);
+	sprintf(io_buffer, isjson
+		? "%s," JSON_SUMMARY "{\"Elapsed\":%.0f,\"MHS av\":%.2f,\"Found Blocks\":%d,\"Getworks\":%d,\"Accepted\":%d,\"Rejected\":%d,\"Hardware Errors\":%d,\"Utility\":%.2f,\"Discarded\":%d,\"Stale\":%d,\"Get Failures\":%d,\"Local Work\":%u,\"Remote Failures\":%u,\"Network Blocks\":%u,\"Total MH\":%.4f}" JSON_CLOSE
+		: "%s" _SUMMARY ",Elapsed=%.0f,MHS av=%.2f,Found Blocks=%d,Getworks=%d,Accepted=%d,Rejected=%d,Hardware Errors=%d,Utility=%.2f,Discarded=%d,Stale=%d,Get Failures=%d,Local Work=%u,Remote Failures=%u,Network Blocks=%u,Total MH=%.4f" SEPSTR,
+		message(MSG_SUMM, 0, NULL, isjson),
+		total_secs, mhs, found_blocks,
+		total_getworks, total_accepted, total_rejected,
+		hw_errors, utility, total_discarded, total_stale,
+		total_go, local_work, total_ro, new_blocks, total_mhashes_done);
 #endif
 #endif
 }
 }
 
 
@@ -1357,10 +1355,10 @@ static void gpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo
 
 
 	strcpy(io_buffer, message(MSG_NUMGPU, 0, NULL, isjson));
 	strcpy(io_buffer, message(MSG_NUMGPU, 0, NULL, isjson));
 
 
-	if (isjson)
-		sprintf(buf, "," JSON_GPUS "{\"Count\":%d}" JSON_CLOSE, nDevs);
-	else
-		sprintf(buf, _GPUS ",Count=%d%c", nDevs, SEPARATOR);
+	sprintf(buf, isjson
+		? "," JSON_GPUS "{\"Count\":%d}" JSON_CLOSE
+		: _GPUS ",Count=%d" SEPSTR,
+		nDevs);
 
 
 	strcat(io_buffer, buf);
 	strcat(io_buffer, buf);
 }
 }
@@ -1370,16 +1368,16 @@ static void pgacount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo
 	char buf[BUFSIZ];
 	char buf[BUFSIZ];
 	int count = 0;
 	int count = 0;
 
 
-#if defined(USE_BITFORCE) || defined(USE_ICARUS)
+#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
 	count = numpgas();
 	count = numpgas();
 #endif
 #endif
 
 
 	strcpy(io_buffer, message(MSG_NUMPGA, 0, NULL, isjson));
 	strcpy(io_buffer, message(MSG_NUMPGA, 0, NULL, isjson));
 
 
-	if (isjson)
-		sprintf(buf, "," JSON_PGAS "{\"Count\":%d}" JSON_CLOSE, count);
-	else
-		sprintf(buf, _PGAS ",Count=%d%c", count, SEPARATOR);
+	sprintf(buf, isjson
+		? "," JSON_PGAS "{\"Count\":%d}" JSON_CLOSE
+		: _PGAS ",Count=%d" SEPSTR,
+		count);
 
 
 	strcat(io_buffer, buf);
 	strcat(io_buffer, buf);
 }
 }
@@ -1395,10 +1393,10 @@ static void cpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo
 
 
 	strcpy(io_buffer, message(MSG_NUMCPU, 0, NULL, isjson));
 	strcpy(io_buffer, message(MSG_NUMCPU, 0, NULL, isjson));
 
 
-	if (isjson)
-		sprintf(buf, "," JSON_CPUS "{\"Count\":%d}" JSON_CLOSE, count);
-	else
-		sprintf(buf, _CPUS ",Count=%d%c", count, SEPARATOR);
+	sprintf(buf, isjson
+		? "," JSON_CPUS "{\"Count\":%d}" JSON_CLOSE
+		: _CPUS ",Count=%d" SEPSTR,
+		count);
 
 
 	strcat(io_buffer, buf);
 	strcat(io_buffer, buf);
 }
 }
@@ -1850,22 +1848,16 @@ void notifystatus(int device, struct cgpu_info *cgpu, bool isjson)
 
 
 	// ALL counters (and only counters) must start the name with a '*'
 	// ALL counters (and only counters) must start the name with a '*'
 	// Simplifies future external support for adding new counters
 	// Simplifies future external support for adding new counters
-	if (isjson)
-		sprintf(buf, "%s{\"NOTIFY\":%d,\"Name\":\"%s\",\"ID\":%d,\"Last Well\":%lu,\"Last Not Well\":%lu,\"Reason Not Well\":\"%s\",\"*Thread Fail Init\":%d,\"*Thread Zero Hash\":%d,\"*Thread Fail Queue\":%d,\"*Dev Sick Idle 60s\":%d,\"*Dev Dead Idle 600s\":%d,\"*Dev Nostart\":%d,\"*Dev Over Heat\":%d,\"*Dev Thermal Cutoff\":%d}" JSON_CLOSE,
-			device > 0 ? "," : "", device, cgpu->api->name, cgpu->device_id,
-			cgpu->device_last_well, cgpu->device_last_not_well, reason,
-			cgpu->thread_fail_init_count, cgpu->thread_zero_hash_count,
-			cgpu->thread_fail_queue_count, cgpu->dev_sick_idle_60_count,
-			cgpu->dev_dead_idle_600_count, cgpu->dev_nostart_count,
-			cgpu->dev_over_heat_count, cgpu->dev_thermal_cutoff_count);
-	else
-		sprintf(buf, "NOTIFY=%d,Name=%s,ID=%d,Last Well=%lu,Last Not Well=%lu,Reason Not Well=%s,*Thread Fail Init=%d,*Thread Zero Hash=%d,*Thread Fail Queue=%d,*Dev Sick Idle 60s=%d,*Dev Dead Idle 600s=%d,*Dev Nostart=%d,*Dev Over Heat=%d,*Dev Thermal Cutoff=%d%c",
-			device, cgpu->api->name, cgpu->device_id,
-			cgpu->device_last_well, cgpu->device_last_not_well, reason,
-			cgpu->thread_fail_init_count, cgpu->thread_zero_hash_count,
-			cgpu->thread_fail_queue_count, cgpu->dev_sick_idle_60_count,
-			cgpu->dev_dead_idle_600_count, cgpu->dev_nostart_count,
-			cgpu->dev_over_heat_count, cgpu->dev_thermal_cutoff_count, SEPARATOR);
+	sprintf(buf, isjson
+		? "%s{\"NOTIFY\":%d,\"Name\":\"%s\",\"ID\":%d,\"Last Well\":%lu,\"Last Not Well\":%lu,\"Reason Not Well\":\"%s\",\"*Thread Fail Init\":%d,\"*Thread Zero Hash\":%d,\"*Thread Fail Queue\":%d,\"*Dev Sick Idle 60s\":%d,\"*Dev Dead Idle 600s\":%d,\"*Dev Nostart\":%d,\"*Dev Over Heat\":%d,\"*Dev Thermal Cutoff\":%d}" JSON_CLOSE
+		: "%sNOTIFY=%d,Name=%s,ID=%d,Last Well=%lu,Last Not Well=%lu,Reason Not Well=%s,*Thread Fail Init=%d,*Thread Zero Hash=%d,*Thread Fail Queue=%d,*Dev Sick Idle 60s=%d,*Dev Dead Idle 600s=%d,*Dev Nostart=%d,*Dev Over Heat=%d,*Dev Thermal Cutoff=%d" SEPSTR,
+		(isjson && (device > 0)) ? COMMA : BLANK,
+		device, cgpu->api->name, cgpu->device_id,
+		cgpu->device_last_well, cgpu->device_last_not_well, reason,
+		cgpu->thread_fail_init_count, cgpu->thread_zero_hash_count,
+		cgpu->thread_fail_queue_count, cgpu->dev_sick_idle_60_count,
+		cgpu->dev_dead_idle_600_count, cgpu->dev_nostart_count,
+		cgpu->dev_over_heat_count, cgpu->dev_thermal_cutoff_count);
 
 
 	strcat(io_buffer, buf);
 	strcat(io_buffer, buf);
 }
 }
@@ -1893,6 +1885,42 @@ static void notify(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool
 		strcat(io_buffer, JSON_CLOSE);
 		strcat(io_buffer, JSON_CLOSE);
 }
 }
 
 
+static void devdetails(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
+{
+	char buf[BUFSIZ];
+	struct cgpu_info *cgpu;
+	int i;
+
+	if (total_devices == 0) {
+		strcpy(io_buffer, message(MSG_NODEVS, 0, NULL, isjson));
+		return;
+	}
+
+	strcpy(io_buffer, message(MSG_DEVDETAILS, 0, NULL, isjson));
+
+	if (isjson) {
+		strcat(io_buffer, COMMA);
+		strcat(io_buffer, JSON_DEVDETAILS);
+	}
+
+	for (i = 0; i < total_devices; i++) {
+		cgpu = devices[i];
+
+		sprintf(buf, isjson
+			? "%s{\"DEVDETAILS\":%d,\"Name\":\"%s\",\"ID\":%d,\"Driver\":\"%s\",\"Kernel\":\"%s\",\"Model\":\"%s\",\"Device Path\":\"%s\"}"
+			: "%sDEVDETAILS=%d,Name=%s,ID=%d,Driver=%s,Kernel=%s,Model=%s,Device Path=%s" SEPSTR,
+			(isjson && (i > 0)) ? COMMA : BLANK,
+			i, cgpu->api->name, cgpu->device_id,
+			cgpu->api->dname, cgpu->kname ? : BLANK,
+			cgpu->name ? : BLANK, cgpu->device_path ? : BLANK);
+
+		strcat(io_buffer, buf);
+	}
+
+	if (isjson)
+		strcat(io_buffer, JSON_CLOSE);
+}
+
 void dosave(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
 void dosave(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
 {
 {
 	FILE *fcfg;
 	FILE *fcfg;
@@ -1938,7 +1966,7 @@ struct CMDS {
 	{ "gpudisable",		gpudisable,	true },
 	{ "gpudisable",		gpudisable,	true },
 	{ "gpurestart",		gpurestart,	true },
 	{ "gpurestart",		gpurestart,	true },
 	{ "gpu",		gpudev,		false },
 	{ "gpu",		gpudev,		false },
-#if defined(USE_BITFORCE) || defined(USE_ICARUS)
+#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX)
 	{ "pga",		pgadev,		false },
 	{ "pga",		pgadev,		false },
 	{ "pgaenable",		pgaenable,	true },
 	{ "pgaenable",		pgaenable,	true },
 	{ "pgadisable",		pgadisable,	true },
 	{ "pgadisable",		pgadisable,	true },
@@ -1963,6 +1991,7 @@ struct CMDS {
 	{ "quit",		doquit,		true },
 	{ "quit",		doquit,		true },
 	{ "privileged",		privileged,	true },
 	{ "privileged",		privileged,	true },
 	{ "notify",		notify,		false },
 	{ "notify",		notify,		false },
+	{ "devdetails",		devdetails,	false },
 	{ NULL,			NULL,		false }
 	{ NULL,			NULL,		false }
 };
 };
 
 
@@ -1976,7 +2005,7 @@ static void send_result(SOCKETTYPE c, bool isjson)
 
 
 	len = strlen(io_buffer);
 	len = strlen(io_buffer);
 
 
-	applog(LOG_DEBUG, "API: send reply: (%d) '%.10s%s'", len+1, io_buffer, len > 10 ? "..." : "");
+	applog(LOG_DEBUG, "API: send reply: (%d) '%.10s%s'", len+1, io_buffer, len > 10 ? "..." : BLANK);
 
 
 	// ignore failure - it's closed immediately anyway
 	// ignore failure - it's closed immediately anyway
 	n = send(c, io_buffer, len+1, 0);
 	n = send(c, io_buffer, len+1, 0);

+ 15 - 0
driver-ztex.c

@@ -307,6 +307,20 @@ static void ztex_statline_before(char *buf, struct cgpu_info *cgpu)
 	}
 	}
 }
 }
 
 
+static json_t*
+get_ztex_extra_device_status(struct cgpu_info *ztex)
+{
+	json_t *info = json_object();
+	struct libztex_device *ztexr = ztex->device_ztex;
+
+	if (ztexr) {
+		double frequency = ztexr->freqM1 * (ztexr->freqM + 1);
+		json_object_set(info, "Frequency", json_real(frequency));
+	}
+
+	return info;
+}
+
 static bool ztex_prepare(struct thr_info *thr)
 static bool ztex_prepare(struct thr_info *thr)
 {
 {
 	struct timeval now;
 	struct timeval now;
@@ -346,6 +360,7 @@ struct device_api ztex_api = {
 	.name = "PGA",
 	.name = "PGA",
 	.api_detect = ztex_detect,
 	.api_detect = ztex_detect,
 	.get_statline_before = ztex_statline_before,
 	.get_statline_before = ztex_statline_before,
+	.get_extra_device_status = get_ztex_extra_device_status,
 	.thread_prepare = ztex_prepare,
 	.thread_prepare = ztex_prepare,
 	.scanhash = ztex_scanhash,
 	.scanhash = ztex_scanhash,
 	.thread_shutdown = ztex_shutdown,
 	.thread_shutdown = ztex_shutdown,

+ 4 - 4
miner.c

@@ -324,10 +324,10 @@ static void applog_and_exit(const char *fmt, ...)
 }
 }
 
 
 static pthread_mutex_t sharelog_lock;
 static pthread_mutex_t sharelog_lock;
-FILE *sharelog_file = NULL;
+static FILE *sharelog_file = NULL;
 
 
-static void
-sharelog(const char*disposition, const struct work*work) {
+static void sharelog(const char*disposition, const struct work*work)
+{
 	if (!sharelog_file)
 	if (!sharelog_file)
 		return;
 		return;
 
 
@@ -361,7 +361,7 @@ sharelog(const char*disposition, const struct work*work) {
 	free(target);
 	free(target);
 	free(hash);
 	free(hash);
 	free(data);
 	free(data);
-	if (rv >= sizeof(s))
+	if (rv >= (int)(sizeof(s)))
 		s[sizeof(s) - 1] = '\0';
 		s[sizeof(s) - 1] = '\0';
 	else
 	else
 	if (rv < 0) {
 	if (rv < 0) {

+ 98 - 16
miner.php

@@ -1,7 +1,7 @@
 <?php
 <?php
 session_start();
 session_start();
 #
 #
-global $miner, $port, $readonly, $notify, $rigs;
+global $miner, $port, $readonly, $notify, $rigs, $socktimeoutsec;
 #
 #
 # Don't touch these 2 - see $rigs below
 # Don't touch these 2 - see $rigs below
 $miner = null;
 $miner = null;
@@ -25,14 +25,30 @@ $notify = true;
 # e.g. $rigs = array('127.0.0.1:4028','myrig.com:4028');
 # e.g. $rigs = array('127.0.0.1:4028','myrig.com:4028');
 $rigs = array('127.0.0.1:4028');
 $rigs = array('127.0.0.1:4028');
 #
 #
+# This should be OK for most cases
+# However, the longer it is the longer you have to wait while php
+# hangs if the target cgminer isn't runnning or listening
+# Feel free to increase it if your network is very slow
+# Also, on some windows PHP, apparently the $usec is ignored
+$socktimeoutsec = 10;
+#
 $here = $_SERVER['PHP_SELF'];
 $here = $_SERVER['PHP_SELF'];
 #
 #
-global $tablebegin, $tableend, $warnfont, $warnoff;
+global $tablebegin, $tableend, $warnfont, $warnoff, $dfmt;
+#
 $tablebegin = '<tr><td><table border=1 cellpadding=5 cellspacing=0>';
 $tablebegin = '<tr><td><table border=1 cellpadding=5 cellspacing=0>';
 $tableend = '</table></td></tr>';
 $tableend = '</table></td></tr>';
 $warnfont = '<font color=red><b>';
 $warnfont = '<font color=red><b>';
 $warnoff = '</b></font>';
 $warnoff = '</b></font>';
-
+$dfmt = 'H:i:s j-M-Y \U\T\CP';
+#
+# Ensure it is only ever shown once
+global $showndate;
+$showndate = false;
+#
+# For summary page to stop retrying failed rigs
+global $rigerror;
+$rigerror = array();
 #
 #
 function htmlhead($checkapi)
 function htmlhead($checkapi)
 {
 {
@@ -80,7 +96,7 @@ $error = null;
 #
 #
 function getsock($addr, $port)
 function getsock($addr, $port)
 {
 {
- global $error;
+ global $error, $socktimeoutsec;
 
 
  $socket = null;
  $socket = null;
  $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
@@ -92,6 +108,11 @@ function getsock($addr, $port)
 	return null;
 	return null;
  }
  }
 
 
+ // Ignore if this fails since the socket connect may work anyway
+ //  and nothing is gained by aborting if the option cannot be set
+ //  since we don't know in advance if it can connect
+ socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec' => $socktimeoutsec, 'usec' => 0));
+
  $res = socket_connect($socket, $addr, $port);
  $res = socket_connect($socket, $addr, $port);
  if ($res === false)
  if ($res === false)
  {
  {
@@ -203,6 +224,8 @@ function getparam($name, $both = false)
 #
 #
 function fmt($section, $name, $value)
 function fmt($section, $name, $value)
 {
 {
+ global $dfmt;
+
  $errorclass = ' class=err';
  $errorclass = ' class=err';
  $warnclass = ' class=warn';
  $warnclass = ' class=warn';
  $b = '&nbsp;';
  $b = '&nbsp;';
@@ -325,6 +348,9 @@ function fmt($section, $name, $value)
 	if ($value != 'Y')
 	if ($value != 'Y')
 		$class = $warnclass;
 		$class = $warnclass;
 	break;
 	break;
+ case 'STATUS.When':
+	$ret = date($dfmt, $value);
+	break;
  }
  }
 
 
  if ($section == 'NOTIFY' && substr($name, 0, 1) == '*' && $value != '0')
  if ($section == 'NOTIFY' && substr($name, 0, 1) == '*' && $value != '0')
@@ -346,7 +372,7 @@ function showhead($cmd, $item, $values)
 
 
  foreach ($values as $name => $value)
  foreach ($values as $name => $value)
  {
  {
-	if ($name == '0')
+	if ($name == '0' or $name == '')
 		$name = '&nbsp;';
 		$name = '&nbsp;';
 	echo "<td valign=bottom class=h>$name</td>";
 	echo "<td valign=bottom class=h>$name</td>";
  }
  }
@@ -360,18 +386,22 @@ function showhead($cmd, $item, $values)
 #
 #
 function details($cmd, $list, $rig)
 function details($cmd, $list, $rig)
 {
 {
- global $tablebegin, $tableend;
+ global $tablebegin, $tableend, $dfmt;
  global $poolcmd, $readonly;
  global $poolcmd, $readonly;
-
- $dfmt = 'H:i:s j-M-Y \U\T\CP';
+ global $showndate;
 
 
  $stas = array('S' => 'Success', 'W' => 'Warning', 'I' => 'Informational', 'E' => 'Error', 'F' => 'Fatal');
  $stas = array('S' => 'Success', 'W' => 'Warning', 'I' => 'Informational', 'E' => 'Error', 'F' => 'Fatal');
 
 
  echo $tablebegin;
  echo $tablebegin;
 
 
- echo '<tr><td class=sta>Date: '.date($dfmt).'</td></tr>';
+ if ($showndate === false)
+ {
+	echo '<tr><td class=sta>Date: '.date($dfmt).'</td></tr>';
 
 
- echo $tableend.$tablebegin;
+	echo $tableend.$tablebegin;
+
+	$showndate = true;
+ }
 
 
  if (isset($list['STATUS']))
  if (isset($list['STATUS']))
  {
  {
@@ -550,18 +580,23 @@ function process($cmds, $rig)
 }
 }
 #
 #
 # $head is a hack but this is just a demo anyway :)
 # $head is a hack but this is just a demo anyway :)
-function doforeach($cmd, $des, $sum, $head)
+function doforeach($cmd, $des, $sum, $head, $datetime)
 {
 {
  global $miner, $port;
  global $miner, $port;
  global $error, $readonly, $notify, $rigs;
  global $error, $readonly, $notify, $rigs;
- global $tablebegin, $tableend, $warnfont, $warnoff;
+ global $tablebegin, $tableend, $warnfont, $warnoff, $dfmt;
+ global $rigerror;
 
 
  $header = $head;
  $header = $head;
  $anss = array();
  $anss = array();
 
 
  $count = 0;
  $count = 0;
+ $preverr = count($rigerror);
  foreach ($rigs as $rig)
  foreach ($rigs as $rig)
  {
  {
+	if (isset($rigerror[$rig]))
+		continue;
+
 	$parts = explode(':', $rig, 2);
 	$parts = explode(':', $rig, 2);
 	if (count($parts) == 2)
 	if (count($parts) == 2)
 	{
 	{
@@ -574,6 +609,7 @@ function doforeach($cmd, $des, $sum, $head)
 		{
 		{
 			echo "<tr><td colspan=100>Error on rig $count getting $des: ";
 			echo "<tr><td colspan=100>Error on rig $count getting $des: ";
 			echo $warnfont.$error.$warnoff.'</td></tr>';
 			echo $warnfont.$error.$warnoff.'</td></tr>';
+			$rigerror[$rig] = $error;
 			$error = null;
 			$error = null;
 		}
 		}
 		else
 		else
@@ -584,10 +620,56 @@ function doforeach($cmd, $des, $sum, $head)
 
 
  if (count($anss) == 0)
  if (count($anss) == 0)
  {
  {
-	echo "<tr><td>Failed to access any rigs successfully</td></tr>";
+	echo '<tr><td>Failed to access any rigs successfully';
+	if ($preverr > 0)
+		echo ' (or rigs had previous errors)';
+	echo '</td></tr>';
 	return;
 	return;
  }
  }
 
 
+ if ($datetime)
+ {
+	echo '<tr><td class=sta>Date: '.date($dfmt).'</td></tr>';
+
+	echo $tableend.$tablebegin;
+
+	$dthead = array('' => 1, 'STATUS' => 1, 'Description' => 1, 'When' => 1);
+	showhead('', null, $dthead);
+
+	foreach ($anss as $rig => $ans)
+	{
+		echo '<tr>';
+
+		foreach ($ans as $item => $row)
+		{
+			if ($item != 'STATUS')
+				continue;
+
+			foreach ($dthead as $name => $x)
+			{
+				if ($name == '')
+					echo "<td align=right><input type=button value='Rig $rig' onclick='pr(\"?rig=$rig\",null)'></td>";
+				else
+				{
+					if (isset($row[$name]))
+						list($showvalue, $class) = fmt('STATUS', $name, $row[$name]);
+					else
+					{
+						$class = '';
+						$showvalue = '&nbsp;';
+					}
+					echo "<td$class align=right>$showvalue</td>";
+				}
+			}
+		}
+
+		echo '</tr>';
+	}
+	echo $tableend;
+	echo '<tr><td><br><br></td></tr>';
+	echo $tablebegin;
+ }
+
  $total = array();
  $total = array();
 
 
  foreach ($anss as $rig => $ans)
  foreach ($anss as $rig => $ans)
@@ -795,15 +877,15 @@ function display()
 
 
  echo $tablebegin;
  echo $tablebegin;
  $sum = array('MHS av', 'Getworks', 'Found Blocks', 'Accepted', 'Rejected', 'Discarded', 'Stale', 'Utility', 'Local Work', 'Total MH');
  $sum = array('MHS av', 'Getworks', 'Found Blocks', 'Accepted', 'Rejected', 'Discarded', 'Stale', 'Utility', 'Local Work', 'Total MH');
- doforeach('summary', 'summary information', $sum, array());
+ doforeach('summary', 'summary information', $sum, array(), true);
  echo $tableend;
  echo $tableend;
  echo '<tr><td><br><br></td></tr>';
  echo '<tr><td><br><br></td></tr>';
  echo $tablebegin;
  echo $tablebegin;
- doforeach('devs', 'device list', $sum, array(''=>'','ID'=>'','Name'=>''));
+ doforeach('devs', 'device list', $sum, array(''=>'','ID'=>'','Name'=>''), false);
  echo $tableend;
  echo $tableend;
  echo '<tr><td><br><br></td></tr>';
  echo '<tr><td><br><br></td></tr>';
  echo $tablebegin;
  echo $tablebegin;
- doforeach('pools', 'pool list', $sum, array(''=>''));
+ doforeach('pools', 'pool list', $sum, array(''=>''), false);
  echo $tableend;
  echo $tableend;
 }
 }
 #
 #