Browse Source

icarus: Replace decisecond-precision read_count with read_timeout_ms (millisecond precision) to handle faster devices like the Antminer U3 that complete works in under 1ds

Luke Dashjr 11 years ago
parent
commit
d50810f29f
6 changed files with 166 additions and 129 deletions
  1. 4 2
      driver-antminer.c
  2. 4 5
      driver-cairnsmore.c
  3. 5 5
      driver-dualminer.c
  4. 145 104
      driver-icarus.c
  5. 5 10
      driver-icarus.h
  6. 3 3
      driver-zeusminer.c

+ 4 - 2
driver-antminer.c

@@ -64,7 +64,7 @@ bool antminer_detect_one(const char *devpath)
 	}
 	}
 	
 	
 	dev->set_device_funcs = antminer_set_device_funcs;
 	dev->set_device_funcs = antminer_set_device_funcs;
-	info->read_count = 15;
+	info->read_timeout_ms = 1500;
 	
 	
 	return true;
 	return true;
 }
 }
@@ -82,6 +82,7 @@ char *antminer_get_clock(struct cgpu_info *cgpu, char *replybuf)
 	unsigned char rebuf[ANTMINER_STATUS_LEN] = {0};
 	unsigned char rebuf[ANTMINER_STATUS_LEN] = {0};
 	
 	
 	struct timeval tv_now;
 	struct timeval tv_now;
+	struct timeval tv_timeout, tv_finish;
 	
 	
 	rdreg_buf[0] = 4;
 	rdreg_buf[0] = 4;
 	rdreg_buf[0] |= 0x80;
 	rdreg_buf[0] |= 0x80;
@@ -103,7 +104,8 @@ char *antminer_get_clock(struct cgpu_info *cgpu, char *replybuf)
 	applog(LOG_DEBUG, "%"PRIpreprv": Get clock: OK", cgpu->proc_repr);
 	applog(LOG_DEBUG, "%"PRIpreprv": Get clock: OK", cgpu->proc_repr);
 	
 	
 	memset(rebuf, 0, sizeof(rebuf));
 	memset(rebuf, 0, sizeof(rebuf));
-	err = icarus_gets(cgpu->proc_repr, rebuf, cgpu->device_fd, &tv_now, NULL, 10, ANTMINER_STATUS_LEN);
+	timer_set_delay(&tv_timeout, &tv_now, 1000000);
+	err = icarus_read(cgpu->proc_repr, rebuf, cgpu->device_fd, &tv_finish, NULL, &tv_timeout, &tv_now, ANTMINER_STATUS_LEN);
 	
 	
 	// Timeout is ok - checking specifically for an error here
 	// Timeout is ok - checking specifically for an error here
 	if (err == ICA_GETS_ERROR)
 	if (err == ICA_GETS_ERROR)

+ 4 - 5
driver-cairnsmore.c

@@ -87,12 +87,11 @@ bool cairnsmore_supports_dynclock(const char * const repr, const int fd)
 
 
 	uint32_t nonce = 0;
 	uint32_t nonce = 0;
 	{
 	{
+		struct timeval tv_now, tv_timeout;
 		struct timeval tv_finish;
 		struct timeval tv_finish;
-		struct thr_info dummy = {
-			.work_restart = false,
-			.work_restart_notifier = {-1, -1},
-		};
-		icarus_gets(repr, (unsigned char*)&nonce, fd, &tv_finish, &dummy, 1, ICARUS_DEFAULT_READ_SIZE);
+		timer_set_now(&tv_now);
+		timer_set_delay(&tv_timeout, &tv_now, 100000);
+		icarus_read(repr, (uint8_t *)&nonce, fd, &tv_finish, NULL, &tv_timeout, &tv_now, ICARUS_DEFAULT_READ_SIZE);
 	}
 	}
 	applog(LOG_DEBUG, "Cairnsmore dynclock detection... Got %08x", nonce);
 	applog(LOG_DEBUG, "Cairnsmore dynclock detection... Got %08x", nonce);
 	switch (nonce) {
 	switch (nonce) {

+ 5 - 5
driver-dualminer.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2013-2014 Luke Dashjr
+ * Copyright 2013-2015 Luke Dashjr
  * Copyright 2014 Nate Woolls
  * Copyright 2014 Nate Woolls
  * Copyright 2014 Dualminer Team
  * Copyright 2014 Dualminer Team
  *
  *
@@ -39,8 +39,8 @@
 #define DUALMINER_SCRYPT_DM_HASH_TIME	0.00003333333333
 #define DUALMINER_SCRYPT_DM_HASH_TIME	0.00003333333333
 #define DUALMINER_SHA2_DM_HASH_TIME     0.00000000300000
 #define DUALMINER_SHA2_DM_HASH_TIME     0.00000000300000
 
 
-#define DUALMINER_SCRYPT_READ_COUNT 48  // 4.8s to read
-#define DUALMINER_SHA2_READ_COUNT	16  // 1.6s to read
+#define DUALMINER_SCRYPT_READ_TIMEOUT_MS 4800  // 4.8s to read
+#define DUALMINER_SHA2_READ_TIMEOUT_MS   1600  // 1.6s to read
 
 
 #define DUALMINER_0_9V_SHA2_UNITS  60
 #define DUALMINER_0_9V_SHA2_UNITS  60
 #define DUALMINER_1_2V_SHA2_UNITS   0
 #define DUALMINER_1_2V_SHA2_UNITS   0
@@ -263,9 +263,9 @@ bool dualminer_detect_one(const char *devpath)
 	}
 	}
 
 
 	if (dualminer_is_scrypt(info))
 	if (dualminer_is_scrypt(info))
-		info->read_count = DUALMINER_SCRYPT_READ_COUNT; // 4.8s to read
+		info->read_timeout_ms = DUALMINER_SCRYPT_READ_TIMEOUT_MS; // 4.8s to read
 	else
 	else
-		info->read_count = DUALMINER_SHA2_READ_COUNT; // 1.6s to read
+		info->read_timeout_ms = DUALMINER_SHA2_READ_TIMEOUT_MS; // 1.6s to read
 
 
 	return true;
 	return true;
 }
 }

+ 145 - 104
driver-icarus.c

@@ -84,8 +84,7 @@ ASSERT1(sizeof(uint32_t) == 4);
 #define ICARUS_READ_COUNT_LIMIT_MAX 100
 #define ICARUS_READ_COUNT_LIMIT_MAX 100
 
 
 // In timing mode: Default starting value until an estimate can be obtained
 // In timing mode: Default starting value until an estimate can be obtained
-// 5 seconds allows for up to a ~840MH/s device
-#define ICARUS_READ_COUNT_TIMING	(5 * TIME_FACTOR)
+#define ICARUS_READ_COUNT_TIMING_MS  75
 
 
 // For a standard Icarus REV3
 // For a standard Icarus REV3
 #define ICARUS_REV3_HASH_TIME 0.00000000264083
 #define ICARUS_REV3_HASH_TIME 0.00000000264083
@@ -130,10 +129,6 @@ ASSERT1(sizeof(uint32_t) == 4);
 // The value above used is doubled each history until it exceeds:
 // The value above used is doubled each history until it exceeds:
 #define MAX_MIN_DATA_COUNT 100
 #define MAX_MIN_DATA_COUNT 100
 
 
-#if (TIME_FACTOR != 10)
-#error TIME_FACTOR must be 10
-#endif
-
 static struct timeval history_sec = { HISTORY_SEC, 0 };
 static struct timeval history_sec = { HISTORY_SEC, 0 };
 
 
 static const char *MODE_DEFAULT_STR = "default";
 static const char *MODE_DEFAULT_STR = "default";
@@ -170,102 +165,126 @@ void icarus_log_protocol(const char * const repr, const void *buf, size_t bufLen
 	applog(LOG_DEBUG, "%"PRIpreprv": DEVPROTO: %s %s", repr, prefix, hex);
 	applog(LOG_DEBUG, "%"PRIpreprv": DEVPROTO: %s %s", repr, prefix, hex);
 }
 }
 
 
-int icarus_gets(const char * const repr, unsigned char *buf, int fd, struct timeval *tv_finish, struct thr_info *thr, int read_count, int read_size)
+int icarus_read(const char * const repr, uint8_t *buf, const int fd, struct timeval * const tvp_finish, struct thr_info * const thr, const struct timeval * const tvp_timeout, struct timeval * const tvp_now, int read_size)
 {
 {
-	ssize_t ret = 0;
-	int rc = 0;
-	int epollfd = -1;
-	int epoll_timeout = ICARUS_READ_FAULT_DECISECONDS * 100;
-	int read_amount = read_size;
+	int rv;
+	long remaining_ms;
+	ssize_t ret;
+	struct timeval tv_start = *tvp_now;
 	bool first = true;
 	bool first = true;
-
+	// If there is no thr, then there's no work restart to watch..
+	
 #ifdef HAVE_EPOLL
 #ifdef HAVE_EPOLL
-	struct epoll_event ev = {
-		.events = EPOLLIN,
-		.data.fd = fd,
-	};
+	bool watching_work_restart = !thr;
+	int epollfd;
 	struct epoll_event evr[2];
 	struct epoll_event evr[2];
-	if (thr && thr->work_restart_notifier[1] != -1) {
+	
 	epollfd = epoll_create(2);
 	epollfd = epoll_create(2);
 	if (epollfd != -1) {
 	if (epollfd != -1) {
+		struct epoll_event ev = {
+			.events = EPOLLIN,
+			.data.fd = fd,
+		};
 		if (-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev)) {
 		if (-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev)) {
+			applog(LOG_DEBUG, "%"PRIpreprv": Error adding %s fd to epoll", "device", repr);
 			close(epollfd);
 			close(epollfd);
 			epollfd = -1;
 			epollfd = -1;
 		}
 		}
+		else
+		if (thr && thr->work_restart_notifier[1] != -1)
 		{
 		{
 			ev.data.fd = thr->work_restart_notifier[0];
 			ev.data.fd = thr->work_restart_notifier[0];
 			if (-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, thr->work_restart_notifier[0], &ev))
 			if (-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, thr->work_restart_notifier[0], &ev))
-				applog(LOG_ERR, "%"PRIpreprv": Error adding work restart fd to epoll", repr);
+				applog(LOG_DEBUG, "%"PRIpreprv": Error adding %s fd to epoll", "work restart", repr);
 			else
 			else
-			{
-				epoll_timeout *= read_count;
-				read_count = 1;
-			}
+				watching_work_restart = true;
 		}
 		}
 	}
 	}
 	else
 	else
-		applog(LOG_ERR, "%"PRIpreprv": Error creating epoll", repr);
-	}
+		applog(LOG_DEBUG, "%"PRIpreprv": Error creating epoll", repr);
+	
+	if (epollfd == -1 && (remaining_ms = timer_remaining_us(tvp_timeout, tvp_now)) < 100000)
+		applog(LOG_WARNING, "%"PRIpreprv": Failed to use epoll, and very short read timeout (%ldms)", repr, remaining_ms);
 #endif
 #endif
-
-	// Read reply 1 byte at a time to get earliest tv_finish
+	
 	while (true) {
 	while (true) {
+		remaining_ms = timer_remaining_us(tvp_timeout, tvp_now) / 1000;
 #ifdef HAVE_EPOLL
 #ifdef HAVE_EPOLL
-		if (epollfd != -1 && (ret = epoll_wait(epollfd, evr, 2, epoll_timeout)) != -1)
+		if (epollfd != -1)
 		{
 		{
-			if (ret == 1 && evr[0].data.fd == fd)
-				ret = read(fd, buf, 1);
-			else
+			if ((!watching_work_restart) && remaining_ms > 100)
+				remaining_ms = 100;
+			ret = epoll_wait(epollfd, evr, 2, remaining_ms);
+			timer_set_now(tvp_now);
+			switch (ret)
 			{
 			{
-				if (ret)
-					notifier_read(thr->work_restart_notifier);
-				ret = 0;
+				case -1:
+					if (unlikely(errno != EINTR))
+						return_via(out, rv = ICA_GETS_ERROR);
+					ret = 0;
+					break;
+				case 0:  // timeout
+					// handled after switch
+					break;
+				case 1:
+					if (evr[0].data.fd != fd)  // must be work restart notifier
+					{
+						notifier_read(thr->work_restart_notifier);
+						ret = 0;
+						break;
+					}
+					// fallthru to...
+				case 2:  // device has data
+					ret = read(fd, buf, read_size);
+					break;
+				default:
+					return_via(out, rv = ICA_GETS_ERROR);
 			}
 			}
 		}
 		}
 		else
 		else
 #endif
 #endif
-		ret = read(fd, buf, 1);
-		if (ret < 0)
-			return ICA_GETS_ERROR;
-
+		{
+			if (remaining_ms > 100)
+				remaining_ms = 100;
+			vcom_set_timeout_ms(fd, remaining_ms);
+			// Read first byte alone to get earliest tv_finish
+			ret = read(fd, buf, first ? 1 : read_size);
+			timer_set_now(tvp_now);
+		}
 		if (first)
 		if (first)
-			cgtime(tv_finish);
-
-		if (ret >= read_amount)
+			*tvp_finish = *tvp_now;
+		if (ret)
 		{
 		{
-			if (epollfd != -1)
-				close(epollfd);
-
+			if (unlikely(ret < 0))
+				return_via(out, rv = ICA_GETS_ERROR);
+			
+			first = false;
+			
 			if (opt_dev_protocol && opt_debug)
 			if (opt_dev_protocol && opt_debug)
-				icarus_log_protocol(repr, buf, read_size, "RECV");
-
-			return ICA_GETS_OK;
-		}
-
-		if (ret > 0) {
+				icarus_log_protocol(repr, buf, ret, "RECV");
+			
+			if (ret >= read_size)
+				return_via(out, rv = ICA_GETS_OK);
+			
+			read_size -= ret;
 			buf += ret;
 			buf += ret;
-			read_amount -= ret;
-			first = false;
+			// Always continue reading while data is coming in, ignoring the timeout
 			continue;
 			continue;
 		}
 		}
-			
-		if (thr && thr->work_restart) {
-			if (epollfd != -1)
-				close(epollfd);
-			applog(LOG_DEBUG, "%"PRIpreprv": Interrupted by work restart", repr);
-			return ICA_GETS_RESTART;
-		}
-
-		rc++;
-		if (rc >= read_count) {
-			if (epollfd != -1)
-				close(epollfd);
-			applog(LOG_DEBUG, "%"PRIpreprv": No data in %.2f seconds",
-			       repr,
-			       (float)rc * epoll_timeout / 1000.);
-			return ICA_GETS_TIMEOUT;
-		}
+		
+		if (thr && thr->work_restart)
+			return_via_applog(out, rv = ICA_GETS_RESTART, LOG_DEBUG, "%"PRIpreprv": Interrupted by work restart", repr);
+		
+		if (timer_passed(tvp_timeout, tvp_now))
+			return_via_applog(out, rv = ICA_GETS_TIMEOUT, LOG_DEBUG, "%"PRIpreprv": No data in %.3f seconds", repr, timer_elapsed_us(&tv_start, tvp_now) / 1e6);
 	}
 	}
+
+out:
+#ifdef HAVE_EPOLL
+	if (epollfd != -1)
+		close(epollfd);
+#endif
+	return rv;
 }
 }
 
 
 int icarus_write(const char * const repr, int fd, const void *buf, size_t bufLen)
 int icarus_write(const char * const repr, int fd, const void *buf, size_t bufLen)
@@ -321,14 +340,14 @@ const char *_icarus_set_timing(struct ICARUS_INFO * const info, const char * con
 
 
 	if (strcasecmp(buf, MODE_SHORT_STR) == 0) {
 	if (strcasecmp(buf, MODE_SHORT_STR) == 0) {
 		// short
 		// short
-		info->read_count = ICARUS_READ_COUNT_TIMING;
+		info->read_timeout_ms = ICARUS_READ_COUNT_TIMING_MS;
 		info->read_count_limit = 0;  // 0 = no limit
 		info->read_count_limit = 0;  // 0 = no limit
 
 
 		info->timing_mode = MODE_SHORT;
 		info->timing_mode = MODE_SHORT;
 		info->do_icarus_timing = true;
 		info->do_icarus_timing = true;
 	} else if (strncasecmp(buf, MODE_SHORT_STREQ, strlen(MODE_SHORT_STREQ)) == 0) {
 	} else if (strncasecmp(buf, MODE_SHORT_STREQ, strlen(MODE_SHORT_STREQ)) == 0) {
 		// short=limit
 		// short=limit
-		info->read_count = ICARUS_READ_COUNT_TIMING;
+		info->read_timeout_ms = ICARUS_READ_COUNT_TIMING_MS;
 
 
 		info->timing_mode = MODE_SHORT;
 		info->timing_mode = MODE_SHORT;
 		info->do_icarus_timing = true;
 		info->do_icarus_timing = true;
@@ -340,14 +359,14 @@ const char *_icarus_set_timing(struct ICARUS_INFO * const info, const char * con
 			info->read_count_limit = ICARUS_READ_COUNT_LIMIT_MAX;
 			info->read_count_limit = ICARUS_READ_COUNT_LIMIT_MAX;
 	} else if (strcasecmp(buf, MODE_LONG_STR) == 0) {
 	} else if (strcasecmp(buf, MODE_LONG_STR) == 0) {
 		// long
 		// long
-		info->read_count = ICARUS_READ_COUNT_TIMING;
+		info->read_timeout_ms = ICARUS_READ_COUNT_TIMING_MS;
 		info->read_count_limit = 0;  // 0 = no limit
 		info->read_count_limit = 0;  // 0 = no limit
 
 
 		info->timing_mode = MODE_LONG;
 		info->timing_mode = MODE_LONG;
 		info->do_icarus_timing = true;
 		info->do_icarus_timing = true;
 	} else if (strncasecmp(buf, MODE_LONG_STREQ, strlen(MODE_LONG_STREQ)) == 0) {
 	} else if (strncasecmp(buf, MODE_LONG_STREQ, strlen(MODE_LONG_STREQ)) == 0) {
 		// long=limit
 		// long=limit
-		info->read_count = ICARUS_READ_COUNT_TIMING;
+		info->read_timeout_ms = ICARUS_READ_COUNT_TIMING_MS;
 
 
 		info->timing_mode = MODE_LONG;
 		info->timing_mode = MODE_LONG;
 		info->do_icarus_timing = true;
 		info->do_icarus_timing = true;
@@ -362,15 +381,18 @@ const char *_icarus_set_timing(struct ICARUS_INFO * const info, const char * con
 		info->Hs = Hs / NANOSEC;
 		info->Hs = Hs / NANOSEC;
 		info->fullnonce = info->Hs * (((double)0xffffffff) + 1);
 		info->fullnonce = info->Hs * (((double)0xffffffff) + 1);
 
 
-		info->read_count = 0;
+		info->read_timeout_ms = 0;
 		if ((eq = strchr(buf, '=')) != NULL)
 		if ((eq = strchr(buf, '=')) != NULL)
-			info->read_count = atoi(eq+1);
+			info->read_timeout_ms = atof(&eq[1]) * 100;
 
 
-		if (info->read_count < 1)
-			info->read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
-
-		if (unlikely(info->read_count < 1))
-			info->read_count = 1;
+		if (info->read_timeout_ms < 1)
+		{
+			info->read_timeout_ms = info->fullnonce * 1000;
+			if (unlikely(info->read_timeout_ms < 2))
+				info->read_timeout_ms = 1;
+			else
+				--info->read_timeout_ms;
+		}
 
 
 		info->read_count_limit = 0;  // 0 = no limit
 		info->read_count_limit = 0;  // 0 = no limit
 		
 		
@@ -381,33 +403,35 @@ const char *_icarus_set_timing(struct ICARUS_INFO * const info, const char * con
 
 
 		info->fullnonce = info->Hs * (((double)0xffffffff) + 1);
 		info->fullnonce = info->Hs * (((double)0xffffffff) + 1);
 
 
-		info->read_count = 0;
+		info->read_timeout_ms = 0;
 		if ((eq = strchr(buf, '=')) != NULL)
 		if ((eq = strchr(buf, '=')) != NULL)
-			info->read_count = atoi(eq+1);
+			info->read_timeout_ms = atof(&eq[1]) * 100;
 
 
-		int def_read_count = ICARUS_READ_COUNT_TIMING;
+		unsigned def_read_timeout_ms = ICARUS_READ_COUNT_TIMING_MS;
 
 
 		if (info->timing_mode == MODE_DEFAULT) {
 		if (info->timing_mode == MODE_DEFAULT) {
 			if (drv == &icarus_drv) {
 			if (drv == &icarus_drv) {
 				info->do_default_detection = 0x10;
 				info->do_default_detection = 0x10;
 			} else {
 			} else {
-				def_read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
+				def_read_timeout_ms = info->fullnonce * 1000;
+				if (def_read_timeout_ms > 0)
+					--def_read_timeout_ms;
 			}
 			}
 
 
 			info->do_icarus_timing = false;
 			info->do_icarus_timing = false;
 		}
 		}
-		if (info->read_count < 1)
-			info->read_count = def_read_count;
+		if (info->read_timeout_ms < 1)
+			info->read_timeout_ms = def_read_timeout_ms;
 		
 		
 		info->read_count_limit = 0;  // 0 = no limit
 		info->read_count_limit = 0;  // 0 = no limit
 	}
 	}
 
 
 	info->min_data_count = MIN_DATA_COUNT;
 	info->min_data_count = MIN_DATA_COUNT;
 
 
-	applog(LOG_DEBUG, "%"PRIpreprv": Init: mode=%s read_count=%d limit=%dms Hs=%e",
+	applog(LOG_DEBUG, "%"PRIpreprv": Init: mode=%s read_timeout_ms=%u limit=%dms Hs=%e",
 		repr,
 		repr,
 		timing_mode_str(info->timing_mode),
 		timing_mode_str(info->timing_mode),
-		info->read_count, info->read_count_limit, info->Hs);
+		info->read_timeout_ms, info->read_count_limit, info->Hs);
 	
 	
 	return NULL;
 	return NULL;
 }
 }
@@ -445,6 +469,7 @@ int icarus_excess_nonce_size(int fd, struct ICARUS_INFO *info)
 
 
 int icarus_probe_work_division(const int fd, const char * const repr, struct ICARUS_INFO * const info)
 int icarus_probe_work_division(const int fd, const char * const repr, struct ICARUS_INFO * const info)
 {
 {
+	struct timeval tv_now, tv_timeout;
 	struct timeval tv_finish;
 	struct timeval tv_finish;
 	
 	
 	// For reading the nonce from Icarus
 	// For reading the nonce from Icarus
@@ -464,7 +489,9 @@ int icarus_probe_work_division(const int fd, const char * const repr, struct ICA
 	
 	
 	icarus_write(repr, fd, pkt, sizeof(pkt));
 	icarus_write(repr, fd, pkt, sizeof(pkt));
 	memset(res_bin, 0, sizeof(res_bin));
 	memset(res_bin, 0, sizeof(res_bin));
-	if (ICA_GETS_OK == icarus_gets(repr, res_bin, fd, &tv_finish, NULL, info->read_count, info->read_size))
+	timer_set_now(&tv_now);
+	timer_set_delay(&tv_timeout, &tv_now, info->read_timeout_ms * 1000);
+	if (ICA_GETS_OK == icarus_read(repr, res_bin, fd, &tv_finish, NULL, &tv_timeout, &tv_now, info->read_size))
 	{
 	{
 		memcpy(&res, res_bin, sizeof(res));
 		memcpy(&res, res_bin, sizeof(res));
 		res = icarus_nonce32toh(info, res);
 		res = icarus_nonce32toh(info, res);
@@ -559,7 +586,10 @@ struct cgpu_info *icarus_detect_custom(const char *devpath, struct device_drv *a
 		// Do not use info->read_size here, instead read exactly ICARUS_NONCE_SIZE
 		// Do not use info->read_size here, instead read exactly ICARUS_NONCE_SIZE
 		// We will then compare the bytes left in fd with info->read_size to determine
 		// We will then compare the bytes left in fd with info->read_size to determine
 		// if this is a valid device
 		// if this is a valid device
-		icarus_gets(devpath, nonce_bin, fd, &tv_finish, NULL, info->probe_read_count, ICARUS_NONCE_SIZE);
+		struct timeval tv_now, tv_timeout;
+		timer_set_now(&tv_now);
+		timer_set_delay(&tv_timeout, &tv_now, info->probe_read_count * 100000);
+		icarus_read(devpath, nonce_bin, fd, &tv_finish, NULL, &tv_timeout, &tv_now, ICARUS_NONCE_SIZE);
 		
 		
 		// How many bytes were left after reading the above nonce
 		// How many bytes were left after reading the above nonce
 		int bytes_left = icarus_excess_nonce_size(fd, info);
 		int bytes_left = icarus_excess_nonce_size(fd, info);
@@ -821,6 +851,7 @@ void handle_identify(struct thr_info * const thr, int ret, const bool was_first_
 	struct icarus_state * const state = thr->cgpu_data;
 	struct icarus_state * const state = thr->cgpu_data;
 	int fd = icarus->device_fd;
 	int fd = icarus->device_fd;
 	struct timeval tv_now;
 	struct timeval tv_now;
+	struct timeval tv_timeout, tv_finish;
 	double delapsed;
 	double delapsed;
 	
 	
 	// For reading the nonce from Icarus
 	// For reading the nonce from Icarus
@@ -847,7 +878,8 @@ void handle_identify(struct thr_info * const thr, int ret, const bool was_first_
 			
 			
 			// Try to get more nonces (ignoring work restart)
 			// Try to get more nonces (ignoring work restart)
 			memset(nonce_bin, 0, sizeof(nonce_bin));
 			memset(nonce_bin, 0, sizeof(nonce_bin));
-			ret = icarus_gets(icarus->proc_repr, nonce_bin, fd, &tv_now, NULL, (info->fullnonce - delapsed) * 10, info->read_size);
+			timer_set_delay(&tv_timeout, &tv_now, (uint64_t)(info->fullnonce - delapsed) * 1000000);
+			ret = icarus_read(icarus->proc_repr, nonce_bin, fd, &tv_finish, NULL, &tv_timeout, &tv_now, info->read_size);
 			if (ret == ICA_GETS_OK)
 			if (ret == ICA_GETS_OK)
 			{
 			{
 				memcpy(&nonce, nonce_bin, sizeof(nonce));
 				memcpy(&nonce, nonce_bin, sizeof(nonce));
@@ -904,6 +936,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	int64_t hash_count;
 	int64_t hash_count;
 	struct timeval tv_start = {.tv_sec=0}, elapsed;
 	struct timeval tv_start = {.tv_sec=0}, elapsed;
 	struct timeval tv_history_start, tv_history_finish;
 	struct timeval tv_history_start, tv_history_finish;
+	struct timeval tv_now, tv_timeout;
 	double Ti, Xi;
 	double Ti, Xi;
 	int i;
 	int i;
 	bool was_hw_error = false;
 	bool was_hw_error = false;
@@ -912,7 +945,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	struct ICARUS_HISTORY *history0, *history;
 	struct ICARUS_HISTORY *history0, *history;
 	int count;
 	int count;
 	double Hs, W, fullnonce;
 	double Hs, W, fullnonce;
-	int read_count;
+	int read_timeout_ms;
 	bool limited;
 	bool limited;
 	uint32_t values;
 	uint32_t values;
 	int64_t hash_count_range;
 	int64_t hash_count_range;
@@ -945,11 +978,13 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 		}
 		}
 		else
 		else
 		{
 		{
-			read_count = info->read_count;
+			read_timeout_ms = info->read_timeout_ms;
 keepwaiting:
 keepwaiting:
 			/* Icarus will return info->read_size bytes nonces or nothing */
 			/* Icarus will return info->read_size bytes nonces or nothing */
 			memset(nonce_bin, 0, sizeof(nonce_bin));
 			memset(nonce_bin, 0, sizeof(nonce_bin));
-			ret = icarus_gets(icarus->proc_repr, nonce_bin, fd, &state->tv_workfinish, thr, read_count, info->read_size);
+			timer_set_now(&tv_now);
+			timer_set_delay(&tv_timeout, &tv_now, read_timeout_ms * 1000);
+			ret = icarus_read(icarus->proc_repr, nonce_bin, fd, &state->tv_workfinish, thr, &tv_timeout, &tv_now, info->read_size);
 			switch (ret) {
 			switch (ret) {
 				case ICA_GETS_RESTART:
 				case ICA_GETS_RESTART:
 					// The prepared work is invalid, and the current work is abandoned
 					// The prepared work is invalid, and the current work is abandoned
@@ -1002,8 +1037,8 @@ keepwaiting:
 			}
 			}
 			if (info->continue_search)
 			if (info->continue_search)
 			{
 			{
-				read_count = info->read_count - ((timer_elapsed_us(&state->tv_workstart, NULL) / (1000000 / TIME_FACTOR)) + 1);
-				if (read_count)
+				read_timeout_ms = info->read_timeout_ms - ((timer_elapsed_us(&state->tv_workstart, NULL) / 1000) + 1);
+				if (read_timeout_ms)
 				{
 				{
 					submit_nonce(icarus_thread_for_nonce(icarus, nonce), nonce_work, nonce);
 					submit_nonce(icarus_thread_for_nonce(icarus, nonce), nonce_work, nonce);
 					goto keepwaiting;
 					goto keepwaiting;
@@ -1126,7 +1161,9 @@ keepwaiting:
 			// Real Icarus?
 			// Real Icarus?
 			if (!info->do_default_detection) {
 			if (!info->do_default_detection) {
 				applog(LOG_DEBUG, "%"PRIpreprv": Seems to be a real Icarus", icarus->proc_repr);
 				applog(LOG_DEBUG, "%"PRIpreprv": Seems to be a real Icarus", icarus->proc_repr);
-				info->read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
+				info->read_timeout_ms = info->fullnonce * 1000;
+				if (info->read_timeout_ms > 0)
+					--info->read_timeout_ms;
 			}
 			}
 		}
 		}
 		else
 		else
@@ -1215,15 +1252,17 @@ keepwaiting:
 			memset(history0, 0, sizeof(struct ICARUS_HISTORY));
 			memset(history0, 0, sizeof(struct ICARUS_HISTORY));
 
 
 			fullnonce = W + Hs * (((double)0xffffffff) + 1);
 			fullnonce = W + Hs * (((double)0xffffffff) + 1);
-			read_count = (int)(fullnonce * TIME_FACTOR) - 1;
-			if (info->read_count_limit > 0 && read_count > info->read_count_limit) {
-				read_count = info->read_count_limit;
+			read_timeout_ms = fullnonce * 1000;
+			if (read_timeout_ms > 0)
+				--read_timeout_ms;
+			if (info->read_count_limit > 0 && read_timeout_ms > info->read_count_limit * 100) {
+				read_timeout_ms = info->read_count_limit * 100;
 				limited = true;
 				limited = true;
 			} else
 			} else
 				limited = false;
 				limited = false;
 
 
 			info->Hs = Hs;
 			info->Hs = Hs;
-			info->read_count = read_count;
+			info->read_timeout_ms = read_timeout_ms;
 
 
 			info->fullnonce = fullnonce;
 			info->fullnonce = fullnonce;
 			info->count = count;
 			info->count = count;
@@ -1237,9 +1276,9 @@ keepwaiting:
 				info->do_icarus_timing = false;
 				info->do_icarus_timing = false;
 
 
 //			applog(LOG_DEBUG, "%"PRIpreprv" Re-estimate: read_count=%d%s fullnonce=%fs history count=%d Hs=%e W=%e values=%d hash range=0x%08lx min data count=%u", icarus->proc_repr, read_count, limited ? " (limited)" : "", fullnonce, count, Hs, W, values, hash_count_range, info->min_data_count);
 //			applog(LOG_DEBUG, "%"PRIpreprv" Re-estimate: read_count=%d%s fullnonce=%fs history count=%d Hs=%e W=%e values=%d hash range=0x%08lx min data count=%u", icarus->proc_repr, read_count, limited ? " (limited)" : "", fullnonce, count, Hs, W, values, hash_count_range, info->min_data_count);
-			applog(LOG_DEBUG, "%"PRIpreprv" Re-estimate: Hs=%e W=%e read_count=%d%s fullnonce=%.3fs",
+			applog(LOG_DEBUG, "%"PRIpreprv" Re-estimate: Hs=%e W=%e read_timeout_ms=%u%s fullnonce=%.3fs",
 					icarus->proc_repr,
 					icarus->proc_repr,
-					Hs, W, read_count,
+					Hs, W, read_timeout_ms,
 					limited ? " (limited)" : "", fullnonce);
 					limited ? " (limited)" : "", fullnonce);
 		}
 		}
 		info->history_count++;
 		info->history_count++;
@@ -1278,7 +1317,9 @@ static struct api_data *icarus_drv_stats(struct cgpu_info *cgpu)
 	// care since hashing performance is way more important than
 	// care since hashing performance is way more important than
 	// locking access to displaying API debug 'stats'
 	// locking access to displaying API debug 'stats'
 	// If locking becomes an issue for any of them, use copy_data=true also
 	// If locking becomes an issue for any of them, use copy_data=true also
-	root = api_add_int(root, "read_count", &(info->read_count), false);
+	const unsigned read_count_ds = info->read_timeout_ms / 100;
+	root = api_add_uint(root, "read_count", &read_count_ds, true);
+	root = api_add_uint(root, "read_timeout_ms", &(info->read_timeout_ms), false);
 	root = api_add_int(root, "read_count_limit", &(info->read_count_limit), false);
 	root = api_add_int(root, "read_count_limit", &(info->read_count_limit), false);
 	root = api_add_double(root, "fullnonce", &(info->fullnonce), false);
 	root = api_add_double(root, "fullnonce", &(info->fullnonce), false);
 	root = api_add_int(root, "count", &(info->count), false);
 	root = api_add_int(root, "count", &(info->count), false);

+ 5 - 10
driver-icarus.h

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2012-2014 Luke Dashjr
+ * Copyright 2012-2015 Luke Dashjr
  * Copyright 2014 Nate Woolls
  * Copyright 2014 Nate Woolls
  * Copyright 2012 Xiangfu
  * Copyright 2012 Xiangfu
  * Copyright 2012 Andrew Smith
  * Copyright 2012 Andrew Smith
@@ -21,11 +21,6 @@
 #include "dynclock.h"
 #include "dynclock.h"
 #include "miner.h"
 #include "miner.h"
 
 
-// Fraction of a second, USB timeout is measured in
-// i.e. 10 means 1/10 of a second
-// Right now, it MUST be 10 due to other assumptions.
-#define TIME_FACTOR 10
-// It's 10 per second, thus value = 10/TIME_FACTOR =
 #define ICARUS_READ_FAULT_DECISECONDS 1
 #define ICARUS_READ_FAULT_DECISECONDS 1
 
 
 #define NANOSEC 1000000000.0
 #define NANOSEC 1000000000.0
@@ -77,8 +72,8 @@ struct ICARUS_INFO {
 	struct ICARUS_HISTORY history[INFO_HISTORY+1];
 	struct ICARUS_HISTORY history[INFO_HISTORY+1];
 	uint32_t min_data_count;
 	uint32_t min_data_count;
 
 
-	// Timeout scanning for a nonce (deciseconds)
-	int read_count;
+	// Timeout scanning for a nonce
+	unsigned read_timeout_ms;
 	// Timeout scanning for a golden nonce (deciseconds)
 	// Timeout scanning for a golden nonce (deciseconds)
 	int probe_read_count;
 	int probe_read_count;
 	
 	
@@ -162,8 +157,8 @@ struct icarus_state {
 };
 };
 
 
 extern struct cgpu_info *icarus_detect_custom(const char *devpath, struct device_drv *, struct ICARUS_INFO *);
 extern struct cgpu_info *icarus_detect_custom(const char *devpath, struct device_drv *, struct ICARUS_INFO *);
-extern int icarus_gets(const char *repr, unsigned char *, int fd, struct timeval *tv_finish, struct thr_info *, int read_count, int read_size);
-extern int icarus_write(const char *repr, int fd, const void *buf, size_t bufLen);
+extern int icarus_read(const char *repr, uint8_t *buf, int fd, struct timeval *tvp_finish, struct thr_info *, const struct timeval *tvp_timeout, struct timeval *tvp_now, int read_size);
+extern int icarus_write(const char * const repr, int fd, const void *buf, size_t bufLen);
 extern bool icarus_init(struct thr_info *);
 extern bool icarus_init(struct thr_info *);
 extern void do_icarus_close(struct thr_info *thr);
 extern void do_icarus_close(struct thr_info *thr);
 extern bool icarus_job_start(struct thr_info *);
 extern bool icarus_job_start(struct thr_info *);

+ 3 - 3
driver-zeusminer.c

@@ -1,7 +1,7 @@
 /*
 /*
  * Copyright 2014 Nate Woolls
  * Copyright 2014 Nate Woolls
  * Copyright 2014 ZeusMiner Team
  * Copyright 2014 ZeusMiner Team
- * Copyright 2014 Luke Dashjr
+ * Copyright 2014-2015 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
  * under the terms of the GNU General Public License as published by the Free
@@ -133,8 +133,8 @@ bool zeusminer_detect_one(const char *devpath)
 	//golden_speed_per_core is the number of hashes / second / core
 	//golden_speed_per_core is the number of hashes / second / core
 	uint64_t golden_speed_per_core = (uint64_t)(hash_count / duration_sec);
 	uint64_t golden_speed_per_core = (uint64_t)(hash_count / duration_sec);
 	//don't combine the following two lines - overflows leaving info->read_count at 0
 	//don't combine the following two lines - overflows leaving info->read_count at 0
-	info->read_count = (uint32_t)((4294967296 * 10) / (ZEUSMINER_CHIP_CORES * chips_count_max * golden_speed_per_core * 2));
-	info->read_count = info->read_count * 3 / 4;
+	info->read_timeout_ms = ((uint64_t)(0x100000000 * 1000)) / (ZEUSMINER_CHIP_CORES * chips_count_max * golden_speed_per_core * 2);
+	info->read_timeout_ms = info->read_timeout_ms * 3 / 4;
 	
 	
 	return true;
 	return true;
 }
 }