/ driver-blockerupter.c
driver-blockerupter.c
  1  #include "config.h"
  2  #include <limits.h>
  3  #include <pthread.h>
  4  #include <stdio.h>
  5  #include <sys/time.h>
  6  #include <sys/types.h>
  7  #include <dirent.h>
  8  #include <unistd.h>
  9  #include <math.h>
 10  #ifndef WIN32
 11  #include <termios.h>
 12  #include <sys/stat.h>
 13  #include <fcntl.h>
 14  #ifndef O_CLOEXEC
 15  #define O_CLOEXEC 0
 16  #endif
 17  #else
 18  #include <io.h>
 19  #endif
 20  
 21  #include "elist.h"
 22  #include "miner.h"
 23  #include "driver-blockerupter.h"
 24  #include "usbutils.h"
 25  
 26  static void blockerupter_space_mode(struct cgpu_info *blockerupter)
 27  {
 28  	int interface;
 29  	unsigned int bits = 0;
 30  
 31  	interface = usb_interface(blockerupter);
 32  
 33  	bits |= CP210X_BITS_DATA_8;
 34  	bits |= CP210X_BITS_PARITY_SPACE;
 35  
 36  	usb_transfer_data(blockerupter, CP210X_TYPE_OUT, CP210X_SET_LINE_CTL, bits, interface, NULL, 0, C_SETPARITY);
 37  }
 38  
 39  static void blockerupter_mark_mode(struct cgpu_info *blockerupter)
 40  {
 41  	int interface;
 42  	unsigned int bits = 0;
 43  
 44  	interface = usb_interface(blockerupter);
 45  
 46  	bits |= CP210X_BITS_DATA_8;
 47  	bits |= CP210X_BITS_PARITY_MARK;
 48  
 49  	usb_transfer_data(blockerupter, CP210X_TYPE_OUT, CP210X_SET_LINE_CTL, bits, interface, NULL, 0, C_SETPARITY);
 50  
 51  }
 52  
 53  static void blockerupter_init_com(struct cgpu_info *blockerupter)
 54  {
 55  	uint32_t baudrate;
 56  	int interface;
 57  
 58  	if (blockerupter->usbinfo.nodev)
 59  		return;
 60  
 61  	interface = usb_interface(blockerupter);
 62  
 63  	// Enable the UART
 64  	usb_transfer_data(blockerupter, CP210X_TYPE_OUT, CP210X_REQUEST_IFC_ENABLE,
 65  			  CP210X_VALUE_UART_ENABLE, interface, NULL, 0, C_ENABLE_UART);
 66  	if (blockerupter->usbinfo.nodev)
 67  		return;
 68  
 69  	// Set data control
 70  	usb_transfer_data(blockerupter, CP210X_TYPE_OUT, CP210X_REQUEST_DATA, CP210X_VALUE_DATA,
 71  			  interface, NULL, 0, C_SETDATA);
 72  
 73  	if (blockerupter->usbinfo.nodev)
 74  		return;
 75  
 76  	// Set the baud
 77  	baudrate = BET_BAUD;
 78  
 79  	usb_transfer_data(blockerupter, CP210X_TYPE_OUT, CP210X_REQUEST_BAUD, 0,
 80  			  interface, &baudrate, sizeof (baudrate), C_SETBAUD);
 81  
 82  	// Set space mode
 83  	blockerupter_space_mode(blockerupter);
 84  }
 85  
 86  static int blockerupter_send(struct cgpu_info *blockerupter, char *data, int len)
 87  {
 88  	int err;
 89  	int bytes_sent;
 90  
 91  	if (unlikely(blockerupter->usbinfo.nodev))
 92  		return SEND_FAIL;
 93  
 94  	err = usb_write(blockerupter, data, len, &bytes_sent, C_BET_WRITE);
 95  
 96  	if (err || bytes_sent != len) {
 97  		applog(LOG_DEBUG, "blockerupter: Send (%d/%d)", bytes_sent, len);
 98  		return SEND_FAIL;
 99  	}
100  
101  	return SEND_OK;
102  }
103  
104  static int blockerupter_read(struct cgpu_info *blockerupter, char *data, int len)
105  {
106  	int err;
107  	int bytes_read;
108  
109  	if (unlikely(blockerupter->usbinfo.nodev))
110  		return READ_FAIL;
111  
112  	err = usb_read_timeout(blockerupter, data, len, &bytes_read, 2, C_BET_READ);
113  
114  	if (err || bytes_read != len) {
115  		applog(LOG_DEBUG, "blockerupter: Read (%d/%d)", bytes_read, len);
116  		return READ_FAIL;
117  	}
118  
119  	return READ_OK;
120  }
121  
122  static void blockerupter_setclock(struct cgpu_info *blockerupter, uint8_t clock)
123  {
124  	struct blockerupter_info *info;
125  	info = blockerupter->device_data;
126  	char command;
127  	int err;
128  
129  	command = C_GCK | clock;
130  	info->clock = clock;
131  	err = blockerupter_send(blockerupter, &command, 1);
132  	if (!err)
133  		applog(LOG_DEBUG, "%s%d: Set Clock to %d MHz", blockerupter->drv->name,
134  		       blockerupter->device_id, (clock + 1) * 10 / 2);
135  }
136  
137  static void blockerupter_setdiff(struct cgpu_info *blockerupter, int diff)
138  {
139  	struct blockerupter_info *info;
140  	info = blockerupter->device_data;
141  	char command,bits;
142  	int err;
143  	int local_diff;
144  
145  	// min_diff for driver is 64
146  	if (diff >= 262144) {
147  		bits = 3;
148  		local_diff = 262144;
149  	} else if (diff >= 4096) {
150  		bits = 2;
151  		local_diff = 4096;
152  	} else {
153  		bits = 1;
154  		local_diff = 64;
155  	}
156  
157  	if (local_diff == info->diff)
158  		return;
159  
160  	command = C_DIF | bits;
161  	err = blockerupter_send(blockerupter, &command, 1);
162  	if (!err) {
163  		applog(LOG_DEBUG, "%s%d: Set Diff Bits to %d", blockerupter->drv->name,
164  		       blockerupter->device_id, bits);
165  		info->diff = local_diff;
166  	}
167  }
168  
169  static void blockerupter_setrolling(struct cgpu_info *blockerupter, uint8_t rolling)
170  {
171  	struct blockerupter_info *info;
172  	info = blockerupter->device_data;
173  	char command;
174  	int err;
175  
176  	command = C_LPO | rolling;
177  	err = blockerupter_send(blockerupter, &command, 1);
178  
179  	if (!err) {
180  		applog(LOG_DEBUG, "%s%d: Set nTime Rolling to %d seconds", blockerupter->drv->name,
181  		       blockerupter->device_id, (rolling + 1) * 30);
182  		info->rolling = (rolling + 1) * 30;
183  	}
184  }
185  
186  static void blockerupter_init(struct cgpu_info *blockerupter)
187  {
188  	struct blockerupter_info *info;
189  
190  	info = blockerupter->device_data;
191  	// Set Clock
192  	if (!opt_bet_clk || opt_bet_clk< 19 || opt_bet_clk > 31) {
193  		opt_bet_clk = BET_CLOCK_DEFAULT;
194  	}
195  	blockerupter_setclock(blockerupter, opt_bet_clk);
196  	info->clock = (opt_bet_clk + 1) * 10;
197  	info->expected = info->clock * 24 * 32 * info->found / 1000.0;
198  	// Set Diff
199  	blockerupter_setdiff(blockerupter, BET_DIFF_DEFAULT);
200  	info->diff = BET_DIFF_DEFAULT;
201  	// Set nTime Rolling
202  	blockerupter_setrolling(blockerupter, BET_ROLLING_DEFAULT);
203  	info->rolling = (BET_ROLLING_DEFAULT + 1) * 30;
204  	cgtime(&info->start_time);
205  }
206  
207  static struct cgpu_info *blockerupter_detect_one(struct libusb_device *dev, struct usb_find_devices *found)
208  {
209  	struct blockerupter_info *info;
210  	struct cgpu_info *blockerupter = usb_alloc_cgpu(&blockerupter_drv, 1);
211  	int i, err;
212  	char reset = C_RES;
213  
214  	if (!usb_init(blockerupter, dev, found)) {
215  		applog(LOG_ERR, "Blockerupter usb init failed");
216  		blockerupter = usb_free_cgpu(blockerupter);
217  		return NULL;
218  	}
219  
220  	blockerupter->device_data = (struct blockerupter_info *) malloc(sizeof(struct blockerupter_info));
221  	info = blockerupter->device_data;
222  	memset(info, 0, sizeof(blockerupter_info));
223  	blockerupter_init_com(blockerupter);
224  
225  	err = blockerupter_send(blockerupter, &reset, 1);
226  	if (err) {
227  		applog(LOG_ERR, "Blockerupter detect failed");
228  		blockerupter = usb_free_cgpu(blockerupter);
229  		return NULL;
230  	}
231  	cgsleep_ms(5000);
232  
233  
234  	for (i = 0; i < BET_MAXBOARDS; i++) {
235  		char detect, answer;
236  
237  		answer = 0;
238  		detect = C_ASK | (uint8_t)i;
239  		blockerupter_send(blockerupter, &detect, 1);
240  		blockerupter_read(blockerupter, &answer, 1);
241  		if (answer == A_WAL) {
242  		     applog(LOG_DEBUG, "BlockErupter found Board: %d", i);
243  		     info->boards[i] = 1;
244  		     info->found++;
245  		} else {
246  			if (!i) {
247  				applog(LOG_DEBUG, "BlockErupter no boards found, likely not BET");
248  				break;
249  			}
250  			applog(LOG_DEBUG, "BlockErupter missing board: %d, received %02x",
251  			       i, answer);
252  		}
253  	}
254  
255  	if (!info->found) {
256  		usb_uninit(blockerupter);
257  		blockerupter = usb_free_cgpu(blockerupter);
258  		free(info);
259  		return NULL;
260  	} else {
261  		blockerupter->threads = 1;
262  		add_cgpu(blockerupter);
263  		applog(LOG_DEBUG, "Add BlockErupter with %d/%d Boards", info->found,
264  		       BET_MAXBOARDS);
265  		blockerupter_init(blockerupter);
266  		return blockerupter;
267  	}
268  }
269  
270  static inline void blockerupter_detect(bool __maybe_unused hotplug)
271  {
272  	usb_detect(&blockerupter_drv, blockerupter_detect_one);
273  }
274  
275  static struct api_data *blockerupter_api_stats(struct cgpu_info *blockerupter)
276  {
277  	struct blockerupter_info *info = blockerupter->device_data;
278  	struct api_data *root = NULL;
279  	struct timeval now, elapsed;
280  	char buf[32];
281  	int i;
282  
283  	cgtime(&now);
284  	timersub(&now, &info->start_time, &elapsed);
285  
286  	info->hashrate = elapsed.tv_sec ? info->hashes * 4.295 / elapsed.tv_sec : 0;
287  	info->eff = info->hashrate / info->expected;
288  
289  	root = api_add_int(root, "Nonces", &info->nonces, false);
290  	root = api_add_uint8(root, "Board", &info->found, false);
291  	root = api_add_int(root, "Clock", &info->clock, false);
292  	root = api_add_int(root,"Accepted", &info->accepted, false);
293  	root = api_add_double(root, "HashRate", &info->hashrate , false);
294  	root = api_add_double(root, "Expected", &info->expected , false);
295  	root = api_add_double(root, "Efficiency", &info->eff, false);
296  	for (i = 0; i < BET_MAXBOARDS; i++) {
297  		double brd_hashrate;
298  
299  		if (info->boards[i]) {
300  		     sprintf(buf, "Board%02d accepted", i);
301  		     root = api_add_int(root, buf, &info->b_info[i].accepted, false);
302  		     sprintf(buf, "Board%02d nonces", i);
303  		     root = api_add_int(root, buf, &info->b_info[i].nonces, false);
304  		     sprintf(buf, "Board%02d hwerror", i);
305  		     root = api_add_double(root, buf, &info->b_info[i].hwe, false);
306  		     sprintf(buf, "Board%02d hashrate", i);
307  		     brd_hashrate = elapsed.tv_sec ? info->b_info[i].hashes * 4.295 / elapsed.tv_sec : 0;
308  		     root = api_add_double(root, buf, &brd_hashrate, false);
309  		}
310  	}
311  
312  	return root;
313  }
314  
315  static bool blockerupter_prepare(struct thr_info *thr)
316  {
317  	struct cgpu_info *blockerupter = thr->cgpu;
318  	struct blockerupter_info *info = blockerupter->device_data;
319  
320  	cglock_init(&(info->pool.data_lock));
321  
322  	return true;
323  }
324  
325  static void blockerupter_sendjob(struct cgpu_info *blockerupter, int board)
326  {
327  	struct blockerupter_info *info = blockerupter->device_data;
328  	struct thr_info *thr = blockerupter->thr[0];
329  	struct work *work;
330  	uint8_t command, answer;
331  	int err;
332  
333  	work = get_work(thr, thr->id);
334  	memcpy(&info->works[info->work_idx],work,sizeof(struct work));
335  
336  	blockerupter_setdiff(blockerupter,floor(work->work_difficulty));
337  
338  	command = C_JOB | (uint8_t)board;
339  	blockerupter_send(blockerupter, (char *)&command, 1);
340  	blockerupter_mark_mode(blockerupter);
341  	cgsleep_ms(1);
342  
343  	blockerupter_send(blockerupter, (char *)(work->midstate), 32);
344  	blockerupter_send(blockerupter, (char *)&(work->data[64]), 12);
345  	blockerupter_send(blockerupter, (char *)&work->nonce2, 4);
346  	blockerupter_send(blockerupter, (char *)&info->work_idx, 1);
347  
348  	cgsleep_ms(1);
349  	blockerupter_space_mode(blockerupter);
350  
351  	answer = 0;
352  	err = blockerupter_read(blockerupter, (char *)&answer, 1);
353  
354  	cgtime(&info->last_job);
355  
356  	if (err || answer != A_GET) {
357  		applog(LOG_ERR, "%s%d: Sync Error", blockerupter->drv->name, blockerupter->device_id);
358  	} else {
359  		info->b_info[board].job_count++;
360  		applog(LOG_DEBUG, "%s%d: Sent work %d to board %d", blockerupter->drv->name,
361  		       blockerupter->device_id, info->work_idx, board);
362  	}
363  
364  	info->work_idx++;
365  	if (info->work_idx >= BET_WORK_FIFO)
366  		info->work_idx = 0;
367  }
368  
369  static uint64_t blockerupter_checknonce(struct cgpu_info *blockerupter, struct blockerupter_response *resp, int board)
370  {
371  	uint8_t test;
372  	struct blockerupter_info *info;
373  	struct thr_info *thr = blockerupter->thr[0];
374  	struct work work;
375  	uint32_t nonce;
376  	uint64_t hashes=0;
377  	int i;
378  	struct board_info *cur_brd;
379  	struct asic_info  *cur_asic;
380  
381  	info = blockerupter->device_data;
382  	work = info->works[resp->work_idx];
383  
384  	nonce = *(uint32_t *)resp->nonce;
385  
386  	applog(LOG_DEBUG, "%s%d: Nonce %08x from board %d, asic %d for work %d",
387  	       blockerupter->drv->name, blockerupter->device_id, *(uint32_t *) resp->nonce,
388  	       board, resp->chip, resp->work_idx);
389  
390  	memcpy(work.data + 4 + 32 + 32, resp->ntime, 4);
391  	__bin2hex(work.ntime, resp->ntime, 4);
392  
393  	info->nonces++;
394  	cur_brd = &info->b_info[board];
395  	cur_brd->nonces++;
396  	cur_asic = &info->b_info[board].asics[resp->chip];
397  	cur_asic->nonces++;
398  
399  	for (i = 0; i < BET_NONCE_FIX; i++) {
400  		test = test_nonce_diff(&work, nonce + i, (double)info->diff);
401  		if (test) {
402  		     applog(LOG_DEBUG, "%s%d: Nonce Fix Pass @%d", blockerupter->drv->name,
403  			    blockerupter->device_id, i);
404  		     info->hashes += info->diff;
405  		     cur_brd->hashes += info->diff;
406  		     cur_asic->hashes += info->diff;
407  		     if (test_nonce_diff(&work, nonce + i, work.work_difficulty)) {
408  			if (submit_nonce(thr, &work, nonce + i)) {
409  				hashes += floor(work.work_difficulty) * (uint64_t) 0xffffffff;
410  				info->accepted++;
411  				cur_brd->accepted++;
412  				cur_asic->accepted++;
413  			}
414  		     }
415  		     break;
416  		}
417  	}
418  
419  	if (i == BET_NONCE_FIX) {
420  		applog(LOG_DEBUG, "%s%d: Nonce Fix Failed", blockerupter->drv->name,
421  		       blockerupter->device_id);
422  		cur_brd->bad++;
423  		cur_brd->hwe = cur_brd->nonces ? (double)cur_brd->bad / cur_brd->nonces : 0;
424  		cur_asic->bad++;
425  		cur_asic->hwe = cur_asic->nonces ? (double)cur_asic->bad / cur_asic->nonces : 0;
426  	}
427  	return hashes;
428  }
429  
430  static uint64_t blockerupter_getresp(struct cgpu_info *blockerupter, int board)
431  {
432  	struct blockerupter_response *resp;
433  	int err;
434  	uint64_t hashes = 0;
435  
436  	resp = (struct blockerupter_response *) malloc(BET_RESP_SZ);
437  	err = blockerupter_read(blockerupter, (char *)resp, BET_RESP_SZ);
438  	if (!err)
439  		hashes = blockerupter_checknonce(blockerupter, resp, board);
440  	free(resp);
441  	return hashes;
442  }
443  
444  static int64_t blockerupter_scanhash(struct thr_info *thr)
445  {
446  	struct cgpu_info *blockerupter = thr->cgpu;
447  	struct blockerupter_info *info = blockerupter->device_data;
448  	char ask;
449  	uint8_t answer;
450  	int i;
451  	int64_t hashes=0;
452  
453  	if (unlikely(blockerupter->usbinfo.nodev)) {
454  		applog(LOG_ERR, "%s%d: Device disappeared, shutting down thread",
455  		       blockerupter->drv->name, blockerupter->device_id);
456  		return -1;
457  	}
458  
459  	for (i = 0; i < BET_MAXBOARDS; i++) {
460  		if (!info->boards[i])
461  			continue;
462  		ask = C_ASK | (uint8_t)i;
463  		blockerupter_send(blockerupter, &ask, 1);
464  		cgsleep_ms(1);
465  		answer = 0;
466  		blockerupter_read(blockerupter, (char *)&answer, 1);
467  
468  		switch (answer) {
469  		case A_WAL:
470  		     blockerupter_sendjob(blockerupter, i);
471  		     break;
472  		case A_YES:
473  		     hashes += blockerupter_getresp(blockerupter, i);
474  		     break;
475  		case A_NO:
476  		     break;
477  		default:
478  		     applog(LOG_ERR, "%s%d: Unexpected value %02x received", blockerupter->drv->name,
479  			    blockerupter->device_id, answer);
480  		     break;
481  		}
482  	}
483  
484  	return hashes;
485  }
486  
487  static void blockerupter_flush_work(struct cgpu_info *blockerupter)
488  {
489  	uint8_t command = C_LPO | BET_ROLLING_DEFAULT;
490  
491  	blockerupter_send(blockerupter, (char *)&command, 1);
492  }
493  
494  struct device_drv blockerupter_drv = {
495  	.drv_id = DRIVER_blockerupter,
496  	.dname = "blockerupter",
497  	.name = "BET",
498  	.min_diff = 64,
499  	.get_api_stats = blockerupter_api_stats,
500  	.drv_detect = blockerupter_detect,
501  	.thread_prepare = blockerupter_prepare,
502  	.hash_work = hash_driver_work,
503  	.flush_work = blockerupter_flush_work,
504  	.scanwork = blockerupter_scanhash
505  };