123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508 |
- #include "config.h"
- #include <limits.h>
- #include <pthread.h>
- #include <stdio.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <dirent.h>
- #include <unistd.h>
- #include <math.h>
- #ifndef WIN32
- #include <termios.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #ifndef O_CLOEXEC
- #define O_CLOEXEC 0
- #endif
- #else
- #ifdef WIN32
- #include <windows.h>
- #endif
- #include <io.h>
- #endif
- #include "elist.h"
- #include "miner.h"
- #include "driver-blockerupter.h"
- #include "usbutils.h"
- static void blockerupter_space_mode(struct cgpu_info *blockerupter)
- {
- int interface;
- unsigned int bits = 0;
- interface = usb_interface(blockerupter);
- bits |= CP210X_BITS_DATA_8;
- bits |= CP210X_BITS_PARITY_SPACE;
- usb_transfer_data(blockerupter, CP210X_TYPE_OUT, CP210X_SET_LINE_CTL, bits, interface, NULL, 0, C_SETPARITY);
- }
- static void blockerupter_mark_mode(struct cgpu_info *blockerupter)
- {
- int interface;
- unsigned int bits = 0;
- interface = usb_interface(blockerupter);
- bits |= CP210X_BITS_DATA_8;
- bits |= CP210X_BITS_PARITY_MARK;
- usb_transfer_data(blockerupter, CP210X_TYPE_OUT, CP210X_SET_LINE_CTL, bits, interface, NULL, 0, C_SETPARITY);
- }
- static void blockerupter_init_com(struct cgpu_info *blockerupter)
- {
- uint32_t baudrate;
- int interface;
- if (blockerupter->usbinfo.nodev)
- return;
- interface = usb_interface(blockerupter);
- // Enable the UART
- usb_transfer_data(blockerupter, CP210X_TYPE_OUT, CP210X_REQUEST_IFC_ENABLE,
- CP210X_VALUE_UART_ENABLE, interface, NULL, 0, C_ENABLE_UART);
- if (blockerupter->usbinfo.nodev)
- return;
- // Set data control
- usb_transfer_data(blockerupter, CP210X_TYPE_OUT, CP210X_REQUEST_DATA, CP210X_VALUE_DATA,
- interface, NULL, 0, C_SETDATA);
- if (blockerupter->usbinfo.nodev)
- return;
- // Set the baud
- baudrate = BET_BAUD;
- usb_transfer_data(blockerupter, CP210X_TYPE_OUT, CP210X_REQUEST_BAUD, 0,
- interface, &baudrate, sizeof (baudrate), C_SETBAUD);
- // Set space mode
- blockerupter_space_mode(blockerupter);
- }
- static int blockerupter_send(struct cgpu_info *blockerupter, char *data, int len)
- {
- int err;
- int bytes_sent;
- if (unlikely(blockerupter->usbinfo.nodev))
- return SEND_FAIL;
- err = usb_write(blockerupter, data, len, &bytes_sent, C_BET_WRITE);
- if (err || bytes_sent != len) {
- applog(LOG_DEBUG, "blockerupter: Send (%d/%d)", bytes_sent, len);
- return SEND_FAIL;
- }
- return SEND_OK;
- }
- static int blockerupter_read(struct cgpu_info *blockerupter, char *data, int len)
- {
- int err;
- int bytes_read;
- if (unlikely(blockerupter->usbinfo.nodev))
- return READ_FAIL;
- err = usb_read_timeout(blockerupter, data, len, &bytes_read, 2, C_BET_READ);
- if (err || bytes_read != len) {
- applog(LOG_DEBUG, "blockerupter: Read (%d/%d)", bytes_read, len);
- return READ_FAIL;
- }
- return READ_OK;
- }
- static void blockerupter_setclock(struct cgpu_info *blockerupter, uint8_t clock)
- {
- struct blockerupter_info *info;
- info = blockerupter->device_data;
- char command;
- int err;
- command = C_GCK | clock;
- info->clock = clock;
- err = blockerupter_send(blockerupter, &command, 1);
- if (!err)
- applog(LOG_DEBUG, "%s%d: Set Clock to %d MHz", blockerupter->drv->name,
- blockerupter->device_id, (clock + 1) * 10 / 2);
- }
- static void blockerupter_setdiff(struct cgpu_info *blockerupter, int diff)
- {
- struct blockerupter_info *info;
- info = blockerupter->device_data;
- char command,bits;
- int err;
- int local_diff;
- // min_diff for driver is 64
- if (diff >= 262144) {
- bits = 3;
- local_diff = 262144;
- } else if (diff >= 4096) {
- bits = 2;
- local_diff = 4096;
- } else {
- bits = 1;
- local_diff = 64;
- }
- if (local_diff == info->diff)
- return;
- command = C_DIF | bits;
- err = blockerupter_send(blockerupter, &command, 1);
- if (!err) {
- applog(LOG_DEBUG, "%s%d: Set Diff Bits to %d", blockerupter->drv->name,
- blockerupter->device_id, bits);
- info->diff = local_diff;
- }
- }
- static void blockerupter_setrolling(struct cgpu_info *blockerupter, uint8_t rolling)
- {
- struct blockerupter_info *info;
- info = blockerupter->device_data;
- char command;
- int err;
- command = C_LPO | rolling;
- err = blockerupter_send(blockerupter, &command, 1);
- if (!err) {
- applog(LOG_DEBUG, "%s%d: Set nTime Rolling to %d seconds", blockerupter->drv->name,
- blockerupter->device_id, (rolling + 1) * 30);
- info->rolling = (rolling + 1) * 30;
- }
- }
- static void blockerupter_init(struct cgpu_info *blockerupter)
- {
- struct blockerupter_info *info;
- info = blockerupter->device_data;
- // Set Clock
- if (!opt_bet_clk || opt_bet_clk< 19 || opt_bet_clk > 31) {
- opt_bet_clk = BET_CLOCK_DEFAULT;
- }
- blockerupter_setclock(blockerupter, opt_bet_clk);
- info->clock = (opt_bet_clk + 1) * 10;
- info->expected = info->clock * 24 * 32 * info->found / 1000.0;
- // Set Diff
- blockerupter_setdiff(blockerupter, BET_DIFF_DEFAULT);
- info->diff = BET_DIFF_DEFAULT;
- // Set nTime Rolling
- blockerupter_setrolling(blockerupter, BET_ROLLING_DEFAULT);
- info->rolling = (BET_ROLLING_DEFAULT + 1) * 30;
- cgtime(&info->start_time);
- }
- static struct cgpu_info *blockerupter_detect_one(struct libusb_device *dev, struct usb_find_devices *found)
- {
- struct blockerupter_info *info;
- struct cgpu_info *blockerupter = usb_alloc_cgpu(&blockerupter_drv, 1);
- int i, err;
- char reset = C_RES;
- if (!usb_init(blockerupter, dev, found)) {
- applog(LOG_ERR, "Blockerupter usb init failed");
- blockerupter = usb_free_cgpu(blockerupter);
- return NULL;
- }
- blockerupter->device_data = (struct blockerupter_info *) malloc(sizeof(struct blockerupter_info));
- info = blockerupter->device_data;
- memset(info, 0, sizeof(blockerupter_info));
- blockerupter_init_com(blockerupter);
- err = blockerupter_send(blockerupter, &reset, 1);
- if (err) {
- applog(LOG_ERR, "Blockerupter detect failed");
- blockerupter = usb_free_cgpu(blockerupter);
- return NULL;
- }
- cgsleep_ms(5000);
- for (i = 0; i < BET_MAXBOARDS; i++) {
- char detect, answer;
- answer = 0;
- detect = C_ASK | (uint8_t)i;
- blockerupter_send(blockerupter, &detect, 1);
- blockerupter_read(blockerupter, &answer, 1);
- if (answer == A_WAL) {
- applog(LOG_DEBUG, "BlockErupter found Board: %d", i);
- info->boards[i] = 1;
- info->found++;
- } else {
- if (!i) {
- applog(LOG_DEBUG, "BlockErupter no boards found, likely not BET");
- break;
- }
- applog(LOG_DEBUG, "BlockErupter missing board: %d, received %02x",
- i, answer);
- }
- }
- if (!info->found) {
- usb_uninit(blockerupter);
- blockerupter = usb_free_cgpu(blockerupter);
- free(info);
- return NULL;
- } else {
- blockerupter->threads = 1;
- add_cgpu(blockerupter);
- applog(LOG_DEBUG, "Add BlockErupter with %d/%d Boards", info->found,
- BET_MAXBOARDS);
- blockerupter_init(blockerupter);
- return blockerupter;
- }
- }
- static inline void blockerupter_detect(bool __maybe_unused hotplug)
- {
- usb_detect(&blockerupter_drv, blockerupter_detect_one);
- }
- static struct api_data *blockerupter_api_stats(struct cgpu_info *blockerupter)
- {
- struct blockerupter_info *info = blockerupter->device_data;
- struct api_data *root = NULL;
- struct timeval now, elapsed;
- char buf[32];
- int i;
- cgtime(&now);
- timersub(&now, &info->start_time, &elapsed);
- info->hashrate = elapsed.tv_sec ? info->hashes * 4.295 / elapsed.tv_sec : 0;
- info->eff = info->hashrate / info->expected;
- root = api_add_int(root, "Nonces", &info->nonces, false);
- root = api_add_uint8(root, "Board", &info->found, false);
- root = api_add_int(root, "Clock", &info->clock, false);
- root = api_add_int(root,"Accepted", &info->accepted, false);
- root = api_add_double(root, "HashRate", &info->hashrate , false);
- root = api_add_double(root, "Expected", &info->expected , false);
- root = api_add_double(root, "Efficiency", &info->eff, false);
- for (i = 0; i < BET_MAXBOARDS; i++) {
- double brd_hashrate;
- if (info->boards[i]) {
- sprintf(buf, "Board%02d accepted", i);
- root = api_add_int(root, buf, &info->b_info[i].accepted, false);
- sprintf(buf, "Board%02d nonces", i);
- root = api_add_int(root, buf, &info->b_info[i].nonces, false);
- sprintf(buf, "Board%02d hwerror", i);
- root = api_add_double(root, buf, &info->b_info[i].hwe, false);
- sprintf(buf, "Board%02d hashrate", i);
- brd_hashrate = elapsed.tv_sec ? info->b_info[i].hashes * 4.295 / elapsed.tv_sec : 0;
- root = api_add_double(root, buf, &brd_hashrate, false);
- }
- }
- return root;
- }
- static bool blockerupter_prepare(struct thr_info *thr)
- {
- struct cgpu_info *blockerupter = thr->cgpu;
- struct blockerupter_info *info = blockerupter->device_data;
- cglock_init(&(info->pool.data_lock));
- return true;
- }
- static void blockerupter_sendjob(struct cgpu_info *blockerupter, int board)
- {
- struct blockerupter_info *info = blockerupter->device_data;
- struct thr_info *thr = blockerupter->thr[0];
- struct work *work;
- uint8_t command, answer;
- int err;
- work = get_work(thr, thr->id);
- memcpy(&info->works[info->work_idx],work,sizeof(struct work));
- blockerupter_setdiff(blockerupter,floor(work->work_difficulty));
- command = C_JOB | (uint8_t)board;
- blockerupter_send(blockerupter, (char *)&command, 1);
- blockerupter_mark_mode(blockerupter);
- cgsleep_ms(1);
- blockerupter_send(blockerupter, (char *)(work->midstate), 32);
- blockerupter_send(blockerupter, (char *)&(work->data[64]), 12);
- blockerupter_send(blockerupter, (char *)&work->nonce2, 4);
- blockerupter_send(blockerupter, (char *)&info->work_idx, 1);
- cgsleep_ms(1);
- blockerupter_space_mode(blockerupter);
- answer = 0;
- err = blockerupter_read(blockerupter, (char *)&answer, 1);
- cgtime(&info->last_job);
- if (err || answer != A_GET) {
- applog(LOG_ERR, "%s%d: Sync Error", blockerupter->drv->name, blockerupter->device_id);
- } else {
- info->b_info[board].job_count++;
- applog(LOG_DEBUG, "%s%d: Sent work %d to board %d", blockerupter->drv->name,
- blockerupter->device_id, info->work_idx, board);
- }
- info->work_idx++;
- if (info->work_idx >= BET_WORK_FIFO)
- info->work_idx = 0;
- }
- static uint64_t blockerupter_checknonce(struct cgpu_info *blockerupter, struct blockerupter_response *resp, int board)
- {
- uint8_t test;
- struct blockerupter_info *info;
- struct thr_info *thr = blockerupter->thr[0];
- struct work work;
- uint32_t nonce;
- uint64_t hashes=0;
- int i;
- struct board_info *cur_brd;
- struct asic_info *cur_asic;
- info = blockerupter->device_data;
- work = info->works[resp->work_idx];
- nonce = *(uint32_t *)resp->nonce;
- applog(LOG_DEBUG, "%s%d: Nonce %08x from board %d, asic %d for work %d",
- blockerupter->drv->name, blockerupter->device_id, *(uint32_t *) resp->nonce,
- board, resp->chip, resp->work_idx);
- memcpy(work.data + 4 + 32 + 32, resp->ntime, 4);
- __bin2hex(work.ntime, resp->ntime, 4);
- info->nonces++;
- cur_brd = &info->b_info[board];
- cur_brd->nonces++;
- cur_asic = &info->b_info[board].asics[resp->chip];
- cur_asic->nonces++;
- for (i = 0; i < BET_NONCE_FIX; i++) {
- test = test_nonce_diff(&work, nonce + i, (double)info->diff);
- if (test) {
- applog(LOG_DEBUG, "%s%d: Nonce Fix Pass @%d", blockerupter->drv->name,
- blockerupter->device_id, i);
- info->hashes += info->diff;
- cur_brd->hashes += info->diff;
- cur_asic->hashes += info->diff;
- if (test_nonce_diff(&work, nonce + i, work.work_difficulty)) {
- if (submit_nonce(thr, &work, nonce + i)) {
- hashes += floor(work.work_difficulty) * (uint64_t) 0xffffffff;
- info->accepted++;
- cur_brd->accepted++;
- cur_asic->accepted++;
- }
- }
- break;
- }
- }
- if (i == BET_NONCE_FIX) {
- applog(LOG_DEBUG, "%s%d: Nonce Fix Failed", blockerupter->drv->name,
- blockerupter->device_id);
- cur_brd->bad++;
- cur_brd->hwe = cur_brd->nonces ? (double)cur_brd->bad / cur_brd->nonces : 0;
- cur_asic->bad++;
- cur_asic->hwe = cur_asic->nonces ? (double)cur_asic->bad / cur_asic->nonces : 0;
- }
- return hashes;
- }
- static uint64_t blockerupter_getresp(struct cgpu_info *blockerupter, int board)
- {
- struct blockerupter_response *resp;
- int err;
- uint64_t hashes = 0;
- resp = (struct blockerupter_response *) malloc(BET_RESP_SZ);
- err = blockerupter_read(blockerupter, (char *)resp, BET_RESP_SZ);
- if (!err)
- hashes = blockerupter_checknonce(blockerupter, resp, board);
- free(resp);
- return hashes;
- }
- static int64_t blockerupter_scanhash(struct thr_info *thr)
- {
- struct cgpu_info *blockerupter = thr->cgpu;
- struct blockerupter_info *info = blockerupter->device_data;
- char ask;
- uint8_t answer;
- int i;
- int64_t hashes=0;
- if (unlikely(blockerupter->usbinfo.nodev)) {
- applog(LOG_ERR, "%s%d: Device disappeared, shutting down thread",
- blockerupter->drv->name, blockerupter->device_id);
- return -1;
- }
- for (i = 0; i < BET_MAXBOARDS; i++) {
- if (!info->boards[i])
- continue;
- ask = C_ASK | (uint8_t)i;
- blockerupter_send(blockerupter, &ask, 1);
- cgsleep_ms(1);
- answer = 0;
- blockerupter_read(blockerupter, (char *)&answer, 1);
- switch (answer) {
- case A_WAL:
- blockerupter_sendjob(blockerupter, i);
- break;
- case A_YES:
- hashes += blockerupter_getresp(blockerupter, i);
- break;
- case A_NO:
- break;
- default:
- applog(LOG_ERR, "%s%d: Unexpected value %02x received", blockerupter->drv->name,
- blockerupter->device_id, answer);
- break;
- }
- }
- return hashes;
- }
- static void blockerupter_flush_work(struct cgpu_info *blockerupter)
- {
- uint8_t command = C_LPO | BET_ROLLING_DEFAULT;
- blockerupter_send(blockerupter, (char *)&command, 1);
- }
- struct device_drv blockerupter_drv = {
- .drv_id = DRIVER_blockerupter,
- .dname = "blockerupter",
- .name = "BET",
- .min_diff = 64,
- .get_api_stats = blockerupter_api_stats,
- .drv_detect = blockerupter_detect,
- .thread_prepare = blockerupter_prepare,
- .hash_work = hash_driver_work,
- .flush_work = blockerupter_flush_work,
- .scanwork = blockerupter_scanhash
- };
|