├── .gitignore ├── CHANGELOG.txt ├── COPYING_GPLv2.txt ├── README.txt ├── core ├── __init__.py ├── actualworksource.py ├── basefrontend.py ├── baseworker.py ├── baseworksource.py ├── blockchain.py ├── core.py ├── fetcher.py ├── inflatable.py ├── job.py ├── objectregistry.py ├── sha256.py ├── startable.py ├── statistics.py ├── util.py ├── workqueue.py └── worksourcegroup.py ├── graveyard └── cursesui.py ├── modules ├── __init__.py ├── fpgamining │ ├── __init__.py │ └── x6500 │ │ ├── __init__.py │ │ ├── boardproxy.py │ │ ├── util │ │ ├── BitstreamReader.py │ │ ├── TAP.py │ │ ├── __init__.py │ │ ├── format.py │ │ ├── fpga.py │ │ ├── ft232r.py │ │ └── jtag.py │ │ ├── x6500hotplug.py │ │ └── x6500worker.py └── theseven │ ├── __init__.py │ ├── basicloggers │ ├── __init__.py │ ├── logfilelogger.py │ └── stderrlogger.py │ ├── bcjsonrpc │ ├── __init__.py │ └── bcjsonrpcworksource.py │ ├── bflsingle │ ├── __init__.py │ ├── bflsinglehotplug.py │ └── bflsingleworker.py │ ├── cairnsmore │ ├── __init__.py │ ├── cairnsmorehotplug.py │ └── cairnsmoreworker.py │ ├── ftdijtag │ ├── __init__.py │ ├── boardproxy.py │ ├── driver.py │ ├── ftdijtaghotplug.py │ └── ftdijtagworker.py │ ├── icarus │ ├── __init__.py │ └── icarusworker.py │ ├── mmq │ ├── __init__.py │ ├── boardproxy.py │ ├── driver.py │ ├── mmqhotplug.py │ └── mmqworker.py │ ├── simplers232 │ ├── __init__.py │ └── simplers232worker.py │ ├── sqlite │ ├── __init__.py │ └── sqlitestats.py │ ├── stratum │ ├── __init__.py │ └── stratumworksource.py │ ├── webui │ ├── __init__.py │ ├── api │ │ ├── __init__.py │ │ ├── blockchaineditor.py │ │ ├── debug.py │ │ ├── frontendeditor.py │ │ ├── gadgethost.py │ │ ├── init.py │ │ ├── log.py │ │ ├── menugadget.py │ │ ├── settingseditor.py │ │ ├── statsgadget.py │ │ ├── uiconfig.py │ │ ├── workereditor.py │ │ └── worksourceeditor.py │ ├── decorators.py │ ├── webui.py │ └── wwwroot │ │ └── static │ │ ├── blockchaineditor │ │ └── blockchaineditor.js │ │ ├── box │ │ └── box.js │ │ ├── contextmenu │ │ └── contextmenu.js │ │ ├── csc │ │ └── csc.js │ │ ├── debugmenu │ │ └── debugmenu.js │ │ ├── debugviewer │ │ └── debugviewer.js │ │ ├── dom │ │ └── dom.js │ │ ├── errorlayer │ │ └── errorlayer.js │ │ ├── event │ │ └── event.js │ │ ├── frontendeditor │ │ └── frontendeditor.js │ │ ├── gadgethost │ │ └── gadgethost.js │ │ ├── init │ │ ├── init.htm │ │ └── loading.gif │ │ ├── json │ │ └── json.js │ │ ├── layer │ │ └── layer.js │ │ ├── layerbox │ │ └── layerbox.js │ │ ├── loggadget │ │ └── loggadget.js │ │ ├── menugadget │ │ └── menugadget.js │ │ ├── nls │ │ └── nls.js │ │ ├── settingseditor │ │ └── settingseditor.js │ │ ├── statsgadget │ │ └── statsgadget.js │ │ ├── storage │ │ └── storage.js │ │ ├── theme │ │ ├── data │ │ │ └── default │ │ │ │ ├── default.css │ │ │ │ ├── default.js │ │ │ │ └── images │ │ │ │ └── closebutton.gif │ │ └── theme.js │ │ ├── uiconfig │ │ └── uiconfig.js │ │ ├── workereditor │ │ └── workereditor.js │ │ └── worksourceeditor │ │ └── worksourceeditor.js │ └── ztex │ ├── __init__.py │ ├── boardproxy.py │ ├── driver.py │ ├── ztexhotplug.py │ └── ztexworker.py └── run-mpbm.py /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.log 3 | *.pyc 4 | usb 5 | __pycache__ 6 | worker/fpgamining/firmware/* 7 | config/* 8 | -------------------------------------------------------------------------------- /CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | Modular Python Bitcoin Miner 2 | Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | 4 | v0.1.0 (final) 5 | =================== 6 | - Handle SIGTERM gracefully 7 | - HTTP keepalive 8 | - Reworked work fetcher architecture (reduce work fetching overshoot, improve load balancing) 9 | - Share upload queueing (upload a limited number of shares in parallel, queue the rest for upload) 10 | - Improved long polling (and long poll aggregation) behavior 11 | - Warmup clock ramping (warm up chips gracefully, yet reach full speed quicker) 12 | - X6500Worker: Upload bitstream only if necessary (uncheck "Force bitstream upload" to enable) 13 | - FTDIJTAGWorker: Detect crashed (deconfigured) FPGAs and reboot them 14 | - WebUI: Add displaying of cgminer-style Utility value and effective hashrate (as seen by pool) 15 | - New frontend module: SQLite statistics logger 16 | - New worker module: FTDIJTAG (replaces X6500, reduces CPU load by 50%) 17 | - New worker module: Cairnsmore (for Enterpoint Cairnsmore1 boards running Glasswalker bitstreams with auto-clocking) 18 | - New worker module: MMQ (for BTCFPGA ModMiner Quad boards) 19 | - Lots of bug fixes and improvements 20 | 21 | v0.1.0 (beta) 22 | =================== 23 | - Completely new architecture -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | Modular Python Bitcoin Miner 2 | Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License 6 | as published by the Free Software Foundation; either version 2 7 | of the License, or (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | 18 | Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | System Requirements 23 | =================== 24 | 25 | MPBM requires Python >= 2.6, most testing is done with Python 3.2. 26 | 27 | The default user interface module uses the python curses module. Most Linux distributions 28 | should have a package for this. Unofficial Windows curses modules are available here: 29 | http://www.lfd.uci.edu/~gohlke/pythonlibs/#curses 30 | 31 | Miner backend modules might use interface modules like PyUSB or PySerial as well. 32 | 33 | 34 | Getting started 35 | =============== 36 | 37 | 1. Install the required prerequisites (see System Requirements above) 38 | 2. Run the following command in the mpbm directory: python run-mpbm.py 39 | 3. Connect to http://localhost:8832 with your favorite web browser 40 | 4. Login with user name "admin" and password "mpbm" 41 | 5. Go to "Frontends", "WebUI" and change the default login credentials 42 | 6. Customize workers and work sources if neccessary 43 | 44 | 45 | Customizing 46 | =========== 47 | 48 | If you don't want to use one of the already supported mining workers, 49 | you will have to write your own worker module. Just duplicate e.g. 50 | the modules/theseven/simplers232 tree and adapt it to fit your needs. 51 | Things are mostly straightforward and that file has more comments than code, 52 | but if you run into trouble or didn't understand some details, feel free to contact 53 | TheSeven (or [7]) on irc.freenode.net. I'll try to help if I have time. 54 | Offering some bitcoins might encourage me to not be lazy :) 55 | -------------------------------------------------------------------------------- /core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSeven/Modular-Python-Bitcoin-Miner/4d3ac96712678191a065a01745fb1ae00610b7df/core/__init__.py -------------------------------------------------------------------------------- /core/actualworksource.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ################################# 24 | # Actual work source base class # 25 | ################################# 26 | 27 | 28 | 29 | import time 30 | import traceback 31 | from binascii import hexlify 32 | from threading import RLock, Thread 33 | from .baseworksource import BaseWorkSource 34 | from .blockchain import DummyBlockchain 35 | 36 | 37 | 38 | class ActualWorkSource(BaseWorkSource): 39 | 40 | nonce_found_async = True 41 | settings = dict(BaseWorkSource.settings, **{ 42 | "errorlimit": {"title": "Error limit", "type": "int", "position": 20000}, 43 | "errorlockout_factor": {"title": "Error lockout factor", "type": "int", "position": 20100}, 44 | "errorlockout_max": {"title": "Error lockout maximum", "type": "int", "position": 20200}, 45 | "stalelockout": {"title": "Stale lockout", "type": "int", "position": 20500}, 46 | }) 47 | 48 | def __init__(self, core, state = None): 49 | super(ActualWorkSource, self).__init__(core, state) 50 | 51 | # Find block chain 52 | self.blockchain = None 53 | if not "blockchain" in self.state: self.state.blockchain = None 54 | self.set_blockchain(core.get_blockchain_by_name(self.state.blockchain)) 55 | 56 | 57 | def _reset(self): 58 | super(ActualWorkSource, self)._reset() 59 | self.signals_new_block = None 60 | self.errors = 0 61 | self.lockoutend = 0 62 | self.estimated_jobs = 1 63 | self.estimated_expiry = 60 64 | 65 | 66 | def _stop(self): 67 | self._cancel_jobs() 68 | super(ActualWorkSource, self)._stop() 69 | 70 | 71 | def _get_statistics(self, stats, childstats): 72 | super(ActualWorkSource, self)._get_statistics(stats, childstats) 73 | stats.signals_new_block = self.signals_new_block 74 | lockout = self.lockoutend - time.time() 75 | stats.locked_out = lockout if lockout > 0 else 0 76 | stats.consecutive_errors = self.errors 77 | stats.jobs_per_request = self.estimated_jobs 78 | stats.job_expiry = self.estimated_expiry 79 | stats.blockchain = self.blockchain 80 | stats.blockchain_id = self.blockchain.id 81 | stats.blockchain_name = "None" if isinstance(self.blockchain, DummyBlockchain) else self.blockchain.settings.name 82 | 83 | 84 | def destroy(self): 85 | super(ActualWorkSource, self).destroy() 86 | if self.blockchain: self.blockchain.remove_work_source(self) 87 | 88 | 89 | def deflate(self): 90 | # Save block chain name to state 91 | blockchain = self.get_blockchain() 92 | if blockchain: self.state.blockchain = blockchain.settings.name 93 | else: self.state.blockchain = None 94 | # Let BaseWorkSource handle own deflation 95 | return super(ActualWorkSource, self).deflate() 96 | 97 | 98 | def apply_settings(self): 99 | super(ActualWorkSource, self).apply_settings() 100 | if not "errorlimit" in self.settings or not self.settings.errorlimit: 101 | self.settings.errorlimit = 3 102 | if not "errorlockout_factor" in self.settings or not self.settings.errorlockout_factor: 103 | self.settings.errorlockout_factor = 10 104 | if not "lockout_max" in self.settings or not self.settings.errorlockout_max: 105 | self.settings.errorlockout_max = 500 106 | if not "stalelockout" in self.settings: self.settings.stalelockout = 25 107 | 108 | 109 | def get_blockchain(self): 110 | if isinstance(self.blockchain, DummyBlockchain): return None 111 | return self.blockchain 112 | 113 | 114 | def set_blockchain(self, blockchain = None): 115 | if self.blockchain: self.blockchain.remove_work_source(self) 116 | self.blockchain = blockchain 117 | if not self.blockchain: self.blockchain = DummyBlockchain(self.core) 118 | if self.blockchain: self.blockchain.add_work_source(self) 119 | 120 | 121 | def _is_locked_out(self): 122 | return time.time() <= self.lockoutend 123 | 124 | 125 | def _handle_success(self, jobs = None): 126 | with self.statelock: 127 | self.errors = 0 128 | if jobs: 129 | jobcount = len(jobs) 130 | self.estimated_jobs = jobcount 131 | self.estimated_expiry = int(jobs[0].expiry - time.time()) 132 | with self.stats.lock: self.stats.jobsreceived += jobcount 133 | 134 | 135 | def _handle_error(self, upload = False): 136 | with self.statelock: 137 | self.errors += 1 138 | if self.errors >= self.settings.errorlimit: 139 | lockout = min(self.settings.errorlockout_factor + self.errors, self.settings.errorlockout_max) 140 | self.lockoutend = max(self.lockoutend, time.time() + lockout) 141 | with self.stats.lock: 142 | if upload: self.stats.uploadretries += 1 143 | else: self.stats.failedjobreqs += 1 144 | 145 | 146 | def _handle_stale(self): 147 | with self.statelock: 148 | self.lockoutend = max(self.lockoutend, time.time() + self.settings.stalelockout) 149 | 150 | 151 | def _push_jobs(self, jobs, source = "unknown source"): 152 | self._handle_success(jobs) 153 | if jobs: 154 | accepted = self.core.workqueue.add_jobs(jobs, self, source) 155 | if accepted != len(jobs): self._handle_stale() 156 | return accepted 157 | else: return 0 158 | 159 | 160 | def get_running_fetcher_count(self): 161 | if not self.started: return 0, 0 162 | return self._get_running_fetcher_count() 163 | 164 | 165 | def start_fetchers(self, count, jobs): 166 | if not self.started or not self.settings.enabled or self._is_locked_out() or not count: return False, 0 167 | started = 0 168 | totaljobs = 0 169 | try: 170 | while started < count: 171 | result, newjobs = self._start_fetcher() 172 | totaljobs += newjobs 173 | if result: 174 | started += result 175 | with self.stats.lock: self.stats.jobrequests += result 176 | if not result or totaljobs >= jobs: 177 | if started: return started, totaljobs 178 | return result, 0 179 | except: 180 | self.core.log(self, "Error while fetching job: %s\n" % (traceback.format_exc()), 200, "y") 181 | self._handle_error() 182 | if started: return started, totaljobs 183 | return False, 0 184 | 185 | 186 | def nonce_found(self, job, data, nonce, noncediff): 187 | if self.nonce_found_async: 188 | thread = Thread(None, self.nonce_found_thread, self.settings.name + "_nonce_found_" + hexlify(nonce).decode("ascii"), (job, data, nonce, noncediff)) 189 | thread.daemon = True 190 | thread.start() 191 | else: self.nonce_found_thread(job, data, nonce, noncediff) 192 | 193 | 194 | def nonce_found_thread(self, job, data, nonce, noncediff): 195 | tries = 0 196 | while True: 197 | try: 198 | result = self._nonce_found(job, data, nonce, noncediff) 199 | self._handle_success() 200 | return job.nonce_handled_callback(nonce, noncediff, result) 201 | except: 202 | self.core.log(self, "Error while sending share %s (difficulty %.5f): %s\n" % (hexlify(nonce).decode("ascii"), noncediff, traceback.format_exc()), 200, "y") 203 | tries += 1 204 | self._handle_error(True) 205 | time.sleep(min(30, tries)) 206 | -------------------------------------------------------------------------------- /core/basefrontend.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ####################### 24 | # Frontend base class # 25 | ####################### 26 | 27 | 28 | 29 | from threading import RLock 30 | from .util import Bunch 31 | from .startable import Startable 32 | from .inflatable import Inflatable 33 | 34 | 35 | 36 | class BaseFrontend(Startable, Inflatable): 37 | 38 | can_log = False 39 | can_show_stats = False 40 | can_configure = False 41 | can_handle_events = False 42 | can_autodetect = False 43 | settings = dict(Inflatable.settings, **{ 44 | "name": {"title": "Name", "type": "string", "position": 100}, 45 | }) 46 | 47 | 48 | def __init__(self, core, state = None): 49 | Inflatable.__init__(self, core, state) 50 | Startable.__init__(self) 51 | self.does_log = self.__class__.can_log 52 | self.does_show_stats = self.__class__.can_show_stats 53 | self.does_handle_events = self.__class__.can_handle_events 54 | 55 | 56 | def destroy(self): 57 | Startable.destroy(self) 58 | Inflatable.destroy(self) 59 | 60 | 61 | def apply_settings(self): 62 | Inflatable.apply_settings(self) 63 | if not "name" in self.settings or not self.settings.name: 64 | self.settings.name = getattr(self.__class__, "default_name", "Untitled frontend") 65 | 66 | 67 | def _reset(self): 68 | self.core.event(300, self, "reset", None, "Resetting frontend state") 69 | Startable._reset(self) 70 | -------------------------------------------------------------------------------- /core/baseworker.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ##################### 24 | # Worker base class # 25 | ##################### 26 | 27 | 28 | 29 | import time 30 | from threading import RLock, Thread 31 | from .util import Bunch 32 | from .statistics import StatisticsProvider 33 | from .startable import Startable 34 | from .inflatable import Inflatable 35 | 36 | 37 | 38 | class BaseWorker(StatisticsProvider, Startable, Inflatable): 39 | 40 | can_autodetect = False 41 | settings = dict(Inflatable.settings, **{ 42 | "name": {"title": "Name", "type": "string", "position": 100}, 43 | }) 44 | 45 | 46 | def __init__(self, core, state = None): 47 | StatisticsProvider.__init__(self) 48 | Inflatable.__init__(self, core, state) 49 | Startable.__init__(self) 50 | 51 | self.children = [] 52 | 53 | 54 | def destroy(self): 55 | Startable.destroy(self) 56 | Inflatable.destroy(self) 57 | 58 | 59 | def apply_settings(self): 60 | Inflatable.apply_settings(self) 61 | if not "name" in self.settings or not self.settings.name: 62 | self.settings.name = getattr(self.__class__, "default_name", "Untitled worker") 63 | 64 | 65 | def _reset(self): 66 | self.core.event(300, self, "reset", None, "Resetting worker state", worker = self) 67 | Startable._reset(self) 68 | self.job = None 69 | self.jobs_per_second = 0 70 | self.parallel_jobs = 0 71 | self.stats.starttime = time.time() 72 | self.stats.ghashes = 0 73 | self.stats.mhps = 0 74 | self.stats.jobsaccepted = 0 75 | self.stats.jobscanceled = 0 76 | self.stats.sharesaccepted = 0 77 | self.stats.sharesrejected = 0 78 | self.stats.sharesinvalid = 0 79 | 80 | 81 | def _get_statistics(self, stats, childstats): 82 | StatisticsProvider._get_statistics(self, stats, childstats) 83 | stats.starttime = self.stats.starttime 84 | stats.ghashes = self.stats.ghashes + childstats.calculatefieldsum("ghashes") 85 | stats.avgmhps = 1000. * stats.ghashes / (time.time() - stats.starttime) 86 | stats.mhps = self.stats.mhps + childstats.calculatefieldsum("mhps") 87 | stats.jobsaccepted = self.stats.jobsaccepted + childstats.calculatefieldsum("jobsaccepted") 88 | stats.jobscanceled = self.stats.jobscanceled + childstats.calculatefieldsum("jobscanceled") 89 | stats.sharesaccepted = self.stats.sharesaccepted + childstats.calculatefieldsum("sharesaccepted") 90 | stats.sharesrejected = self.stats.sharesrejected + childstats.calculatefieldsum("sharesrejected") 91 | stats.sharesinvalid = self.stats.sharesinvalid + childstats.calculatefieldsum("sharesinvalid") 92 | stats.parallel_jobs = self.parallel_jobs + childstats.calculatefieldsum("parallel_jobs") 93 | stats.current_job = self.job 94 | stats.current_work_source = getattr(stats.current_job, "worksource", None) if stats.current_job else None 95 | stats.current_work_source_id = stats.current_work_source.id if stats.current_work_source else None 96 | stats.current_work_source_name = stats.current_work_source.settings.name if stats.current_work_source else None 97 | 98 | 99 | def get_jobs_per_second(self): 100 | result = self.jobs_per_second 101 | for child in self.children: result += child.get_jobs_per_second() 102 | return result 103 | 104 | def get_parallel_jobs(self): 105 | result = self.parallel_jobs 106 | for child in self.children: result += child.get_parallel_jobs() 107 | return result 108 | -------------------------------------------------------------------------------- /core/baseworksource.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ########################## 24 | # Work source base class # 25 | ########################## 26 | 27 | 28 | 29 | import time 30 | from threading import RLock 31 | from .util import Bunch 32 | from .statistics import StatisticsProvider 33 | from .startable import Startable 34 | from .inflatable import Inflatable 35 | 36 | 37 | 38 | class BaseWorkSource(StatisticsProvider, Startable, Inflatable): 39 | 40 | is_group = False 41 | settings = dict(Inflatable.settings, **{ 42 | "name": {"title": "Name", "type": "string", "position": 100}, 43 | "enabled": {"title": "Enabled", "type": "boolean", "position": 200}, 44 | "hashrate": {"title": "Hashrate", "type": "float", "position": 10000}, 45 | "priority": {"title": "Priority", "type": "float", "position": 10100}, 46 | }) 47 | 48 | 49 | def __init__(self, core, state = None): 50 | StatisticsProvider.__init__(self) 51 | Inflatable.__init__(self, core, state) 52 | Startable.__init__(self) 53 | 54 | self.parent = None 55 | self.statelock = RLock() 56 | 57 | 58 | def destroy(self): 59 | Startable.destroy(self) 60 | Inflatable.destroy(self) 61 | 62 | 63 | def apply_settings(self): 64 | Inflatable.apply_settings(self) 65 | if not "name" in self.settings or not self.settings.name: 66 | self.settings.name = getattr(self.__class__, "default_name", "Untitled work source") 67 | if not "enabled" in self.settings: self.settings.enabled = True 68 | if not "hashrate" in self.settings: self.settings.hashrate = 0 69 | if not "priority" in self.settings: self.settings.priority = 1 70 | 71 | 72 | def _reset(self): 73 | self.core.event(300, self, "reset", None, "Resetting work source state", worksource = self) 74 | Startable._reset(self) 75 | self.mhashes_pending = 0 76 | self.mhashes_deferred = 0 77 | self.stats.starttime = time.time() 78 | self.stats.ghashes = 0 79 | self.stats.jobrequests = 0 80 | self.stats.failedjobreqs = 0 81 | self.stats.uploadretries = 0 82 | self.stats.jobsreceived = 0 83 | self.stats.jobsaccepted = 0 84 | self.stats.jobscanceled = 0 85 | self.stats.sharesaccepted = 0 86 | self.stats.sharesrejected = 0 87 | self.stats.difficulty = 0 88 | self.jobs = [] 89 | 90 | 91 | def _get_statistics(self, stats, childstats): 92 | StatisticsProvider._get_statistics(self, stats, childstats) 93 | stats.starttime = self.stats.starttime 94 | stats.ghashes = self.stats.ghashes + childstats.calculatefieldsum("ghashes") 95 | stats.avgmhps = 1000. * self.stats.ghashes / (time.time() - stats.starttime) + childstats.calculatefieldsum("avgmhps") 96 | stats.jobrequests = self.stats.jobrequests + childstats.calculatefieldsum("jobrequests") 97 | stats.failedjobreqs = self.stats.failedjobreqs + childstats.calculatefieldsum("failedjobreqs") 98 | stats.uploadretries = self.stats.uploadretries + childstats.calculatefieldsum("uploadretries") 99 | stats.jobsreceived = self.stats.jobsreceived + childstats.calculatefieldsum("jobsreceived") 100 | stats.jobsaccepted = self.stats.jobsaccepted + childstats.calculatefieldsum("jobsaccepted") 101 | stats.jobscanceled = self.stats.jobscanceled + childstats.calculatefieldsum("jobscanceled") 102 | stats.sharesaccepted = self.stats.sharesaccepted + childstats.calculatefieldsum("sharesaccepted") 103 | stats.sharesrejected = self.stats.sharesrejected + childstats.calculatefieldsum("sharesrejected") 104 | stats.difficulty = self.stats.difficulty 105 | 106 | 107 | def set_parent(self, parent = None): 108 | self.parent = parent 109 | 110 | 111 | def get_parent(self): 112 | return self.parent 113 | 114 | 115 | def add_job(self, job): 116 | if not job in self.jobs: self.jobs.append(job) 117 | 118 | 119 | def remove_job(self, job): 120 | while job in self.jobs: self.jobs.remove(job) 121 | 122 | 123 | def _cancel_jobs(self, graceful = False): 124 | cancel = [] 125 | with self.core.workqueue.lock: 126 | while self.jobs: 127 | job = self.jobs.pop(0) 128 | if job.worker: cancel.append(job) 129 | else: job.destroy() 130 | if not graceful: self.jobs = [] 131 | self.core.workqueue.cancel_jobs(cancel, graceful) 132 | 133 | 134 | def add_pending_mhashes(self, mhashes): 135 | with self.statelock: self.mhashes_pending += mhashes 136 | if self.parent: self.parent.add_pending_mhashes(mhashes) 137 | 138 | 139 | def add_deferred_mhashes(self, mhashes): 140 | with self.statelock: self.mhashes_deferred += mhashes 141 | if self.parent: self.parent.add_deferred_mhashes(mhashes) 142 | -------------------------------------------------------------------------------- /core/blockchain.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ####################### 24 | # Block chain manager # 25 | ####################### 26 | 27 | 28 | 29 | import time 30 | from threading import RLock 31 | from .util import Bunch 32 | from .statistics import StatisticsProvider, StatisticsList 33 | from .startable import Startable 34 | from .inflatable import Inflatable 35 | 36 | 37 | 38 | class Blockchain(StatisticsProvider, Startable, Inflatable): 39 | 40 | settings = dict(Inflatable.settings, **{ 41 | "name": {"title": "Name", "type": "string", "position": 100}, 42 | "timeout": {"title": "History timeout", "type": "float", "position": 1000}, 43 | }) 44 | 45 | 46 | def __init__(self, core, state = None): 47 | StatisticsProvider.__init__(self) 48 | Inflatable.__init__(self, core, state) 49 | Startable.__init__(self) 50 | 51 | self.worksourcelock = RLock() 52 | self.blocklock = RLock() 53 | 54 | 55 | def destroy(self): 56 | with self.worksourcelock: 57 | for worksource in self.children: 58 | worksource.set_blockchain(None) 59 | Startable.destroy(self) 60 | Inflatable.destroy(self) 61 | 62 | 63 | def apply_settings(self): 64 | Inflatable.apply_settings(self) 65 | if not "name" in self.settings or not self.settings.name: 66 | self.settings.name = "Untitled blockchain" 67 | with self.core.blockchainlock: 68 | origname = self.settings.name 69 | self.settings.name = None 70 | name = origname 71 | i = 1 72 | while self.core.get_blockchain_by_name(name): 73 | i += 1 74 | name = origname + (" (%d)" % i) 75 | self.settings.name = name 76 | if not "timeout" in self.settings: self.settings.timeout = 60 77 | 78 | 79 | def _reset(self): 80 | self.core.event(300, self, "reset", None, "Resetting blockchain state", blockchain = self) 81 | Startable._reset(self) 82 | self.currentprevhash = None 83 | self.knownprevhashes = [] 84 | self.timeoutend = 0 85 | self.jobs = [] 86 | self.stats.starttime = time.time() 87 | self.stats.blocks = 0 88 | self.stats.lastblock = None 89 | 90 | 91 | def _get_statistics(self, stats, childstats): 92 | StatisticsProvider._get_statistics(self, stats, childstats) 93 | stats.starttime = self.stats.starttime 94 | stats.blocks = self.stats.blocks 95 | stats.lastblock = self.stats.lastblock 96 | stats.ghashes = childstats.calculatefieldsum("ghashes") 97 | stats.avgmhps = childstats.calculatefieldsum("avgmhps") 98 | stats.jobsreceived = childstats.calculatefieldsum("jobsreceived") 99 | stats.jobsaccepted = childstats.calculatefieldsum("jobsaccepted") 100 | stats.jobscanceled = childstats.calculatefieldsum("jobscanceled") 101 | stats.sharesaccepted = childstats.calculatefieldsum("sharesaccepted") 102 | stats.sharesrejected = childstats.calculatefieldsum("sharesrejected") 103 | stats.children = [] 104 | 105 | 106 | def add_job(self, job): 107 | if not job in self.jobs: self.jobs.append(job) 108 | 109 | 110 | def remove_job(self, job): 111 | while job in self.jobs: self.jobs.remove(job) 112 | 113 | 114 | def add_work_source(self, worksource): 115 | with self.worksourcelock: 116 | if not worksource in self.children: self.children.append(worksource) 117 | 118 | 119 | def remove_work_source(self, worksource): 120 | with self.worksourcelock: 121 | while worksource in self.children: self.children.remove(worksource) 122 | 123 | 124 | def check_job(self, job): 125 | if self.currentprevhash == job.prevhash: return True 126 | cancel = [] 127 | # Needs to be locked outside of blocklock to prevent race condition 128 | with self.core.workqueue.lock: 129 | with self.blocklock: 130 | now = time.time() 131 | timeout_expired = now > self.timeoutend 132 | self.timeoutend = now + self.settings.timeout 133 | if job.prevhash in self.knownprevhashes: return False 134 | if timeout_expired: self.knownprevhashes = [self.currentprevhash] 135 | else: self.knownprevhashes.append(self.currentprevhash) 136 | self.currentprevhash = job.prevhash 137 | while self.jobs: 138 | job = self.jobs.pop(0) 139 | if job.worker: cancel.append(job) 140 | else: job.destroy() 141 | self.jobs = [] 142 | with self.stats.lock: 143 | self.stats.blocks += 1 144 | self.stats.lastblock = now 145 | self.core.log(self, "New block detected\n", 300, "B") 146 | self.core.workqueue.cancel_jobs(cancel) 147 | return True 148 | 149 | 150 | 151 | class DummyBlockchain(object): 152 | 153 | 154 | def __init__(self, core): 155 | self.core = core 156 | self.id = 0 157 | self.settings = Bunch(name = "Dummy blockchain") 158 | 159 | # Initialize job list (protected by global job queue lock) 160 | self.jobs = [] 161 | self.currentprevhash = None 162 | self.knownprevhashes = [] 163 | self.timeoutend = 0 164 | self.blocklock = RLock() 165 | 166 | 167 | def add_job(self, job): 168 | if not job in self.jobs: self.jobs.append(job) 169 | 170 | 171 | def remove_job(self, job): 172 | while job in self.jobs: self.jobs.remove(job) 173 | 174 | 175 | def add_work_source(self, worksource): 176 | pass 177 | 178 | 179 | def remove_work_source(self, worksource): 180 | pass 181 | 182 | 183 | def check_job(self, job): 184 | if self.currentprevhash == job.prevhash: return True 185 | cancel = [] 186 | # Needs to be locked outside of blocklock to prevent race condition 187 | with self.core.workqueue.lock: 188 | with self.blocklock: 189 | now = time.time() 190 | timeout_expired = now > self.timeoutend 191 | self.timeoutend = now + 10 192 | if job.prevhash in self.knownprevhashes: return False 193 | if timeout_expired: self.knownprevhashes = [self.currentprevhash] 194 | else: self.knownprevhashes.append(self.currentprevhash) 195 | self.currentprevhash = job.prevhash 196 | while self.jobs: 197 | job = self.jobs.pop(0) 198 | if job.worker: cancel.append(job) 199 | else: job.destroy() 200 | self.jobs = [] 201 | self.core.log(self, "New block detected\n", 300, "B") 202 | self.core.workqueue.cancel_jobs(cancel) 203 | return True 204 | 205 | -------------------------------------------------------------------------------- /core/fetcher.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ################ 24 | # Work fetcher # 25 | ################ 26 | 27 | 28 | 29 | import time 30 | import traceback 31 | from threading import RLock, Condition, Thread, current_thread 32 | from .startable import Startable 33 | from .util import Bunch 34 | 35 | 36 | 37 | class Fetcher(Startable): 38 | 39 | 40 | def __init__(self, core): 41 | self.core = core 42 | self.id = -2 43 | self.settings = Bunch(name = "Fetcher controller") 44 | super(Fetcher, self).__init__() 45 | # Initialize global fetcher lock and wakeup condition 46 | self.lock = Condition() 47 | # Fetcher controller thread 48 | self.controllerthread = None 49 | 50 | 51 | def _reset(self): 52 | self.core.event(300, self, "reset", None, "Resetting fetcher state") 53 | super(Fetcher, self)._reset() 54 | self.speedchanged = True 55 | self.queuetarget = 5 56 | 57 | 58 | def _start(self): 59 | super(Fetcher, self)._start() 60 | self.shutdown = False 61 | self.controllerthread = Thread(None, self.controllerloop, "fetcher_controller") 62 | self.controllerthread.daemon = True 63 | self.controllerthread.start() 64 | 65 | 66 | def _stop(self): 67 | self.shutdown = True 68 | self.wakeup() 69 | self.controllerthread.join(10) 70 | super(Fetcher, self)._stop() 71 | 72 | 73 | def wakeup(self): 74 | with self.lock: self.lock.notify() 75 | 76 | 77 | def notify_speed_changed(self, worker): 78 | with self.lock: 79 | self.speedchanged = True 80 | self.lock.notify() 81 | 82 | 83 | def controllerloop(self): 84 | with self.lock: 85 | while not self.shutdown: 86 | if self.speedchanged: 87 | self.speedchanged = False 88 | jobspersecond = 0 89 | paralleljobs = 0 90 | with self.core.workerlock: 91 | for worker in self.core.workers: 92 | jobspersecond += worker.get_jobs_per_second() 93 | paralleljobs += worker.get_parallel_jobs() 94 | self.queuetarget = max(5, paralleljobs * 2, jobspersecond * 30) 95 | self.core.workqueue.target = self.queuetarget 96 | 97 | worksource = self.core.get_root_work_source() 98 | queuecount = self.core.workqueue.count 99 | fetchercount, jobcount = worksource.get_running_fetcher_count() 100 | needjobs = self.queuetarget - queuecount - jobcount 101 | startfetchers = max(0, min(5, (self.queuetarget - queuecount - jobcount // 2) // 2)) 102 | if not startfetchers and queuecount == 0 and fetchercount < 3: startfetchers = 1 103 | if not startfetchers: 104 | if self.core.workqueue.count * 2 > self.queuetarget: self.lock.wait() 105 | else: self.lock.wait(0.1) 106 | continue 107 | try: 108 | if startfetchers: 109 | started, startedjobs = worksource.start_fetchers(startfetchers if self.core.workqueue.count * 4 < self.queuetarget else 1, needjobs) 110 | if not started: 111 | self.lock.wait(0.1) 112 | continue 113 | else: self.lock.wait(0.1) 114 | lockout = time.time() + min(5, 4 * self.core.workqueue.count / self.queuetarget - 1) 115 | while time.time() < lockout and self.core.workqueue.count > self.queuetarget / 4: self.lock.wait(0.1) 116 | except: 117 | self.core.log(self, "Error while starting fetcher thread: %s\n" % traceback.format_exc(), 100, "rB") 118 | time.sleep(1) 119 | -------------------------------------------------------------------------------- /core/inflatable.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ############################# 24 | # In-/Deflatable base class # 25 | ############################# 26 | 27 | 28 | 29 | from .util import Bunch 30 | 31 | 32 | 33 | class Inflatable(object): 34 | 35 | settings = {} 36 | 37 | 38 | def __init__(self, core, state = None): 39 | self.core = core 40 | self.started = False 41 | 42 | # Create and populate a new state dict if neccessary 43 | if not state: 44 | state = Bunch() 45 | state.settings = Bunch() 46 | self.is_new_instance = True 47 | else: self.is_new_instance = False 48 | self.state = state 49 | 50 | # Grab the settings from the state 51 | self.settings = state.settings 52 | self.apply_settings() 53 | 54 | # Register ourselves in the global object registry 55 | self.id = core.registry.register(self) 56 | 57 | 58 | def destroy(self): 59 | # Unregister ourselves from the global object registry 60 | self.core.registry.unregister(self.id) 61 | 62 | 63 | def apply_settings(self): 64 | pass 65 | 66 | 67 | def deflate(self): 68 | return (self.__class__, self.state) 69 | 70 | 71 | @staticmethod 72 | def inflate(core, state): 73 | if not state: return None 74 | return state[0](core, state[1]) 75 | -------------------------------------------------------------------------------- /core/objectregistry.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ################### 24 | # Object registry # 25 | ################### 26 | 27 | 28 | 29 | from threading import RLock 30 | 31 | 32 | 33 | class ObjectRegistry(object): 34 | 35 | 36 | def __init__(self, core): 37 | self.core = core 38 | self.lock = RLock() 39 | self.current_id = 0 40 | self.objects = {} 41 | 42 | 43 | def register(self, obj): 44 | with self.lock: 45 | self.current_id += 1 46 | self.objects[self.current_id] = obj 47 | return self.current_id 48 | 49 | 50 | def unregister(self, id): 51 | try: del self.objects[id] 52 | except: pass 53 | 54 | 55 | def get(self, id): 56 | return self.objects[id] 57 | -------------------------------------------------------------------------------- /core/sha256.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ######################### 24 | # SHA256 implementation # 25 | ######################### 26 | 27 | 28 | 29 | import struct 30 | 31 | 32 | 33 | class SHA256(object): 34 | 35 | _k = (0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 36 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 37 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 38 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 39 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 40 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 41 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 42 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2) 43 | 44 | 45 | def __init__(self): 46 | self._buffer = b"" 47 | self._length = 0 48 | self.state = (0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19) 49 | 50 | 51 | def _rotr(self, x, y): 52 | return ((x >> y) | (x << (32 - y))) & 0xffffffff 53 | 54 | 55 | def _round(self, data): 56 | w = [0] * 64 57 | w[0:15] = struct.unpack("!16L", data) 58 | 59 | for i in range(16, 64): 60 | s0 = self._rotr(w[i - 15], 7) ^ self._rotr(w[i - 15], 18) ^ (w[i - 15] >> 3) 61 | s1 = self._rotr(w[i - 2], 17) ^ self._rotr(w[i - 2], 19) ^ (w[i - 2] >> 10) 62 | w[i] = (w[i - 16] + s0 + w[i - 7] + s1) & 0xffffffff 63 | 64 | a, b, c, d, e, f, g, h = self.state 65 | 66 | for i in range(64): 67 | t1 = h + (self._rotr(e, 6) ^ self._rotr(e, 11) ^ self._rotr(e, 25)) + ((e & f) ^ ((~e) & g)) + self._k[i] + w[i] 68 | t2 = (self._rotr(a, 2) ^ self._rotr(a, 13) ^ self._rotr(a, 22)) + ((a & b) ^ (a & c) ^ (b & c)) 69 | h, g, f, e, d, c, b, a = g, f, e, (d + t1) & 0xffffffff, c, b, a, (t1 + t2) & 0xffffffff 70 | 71 | self.state = tuple((x + y) & 0xffffffff for x, y in zip(self.state, (a, b, c, d, e, f, g, h))) 72 | 73 | 74 | def update(self, data): 75 | self._buffer += data 76 | self._length += len(data) 77 | while len(self._buffer) >= 64: 78 | self._round(self._buffer[:64]) 79 | self._buffer = self._buffer[64:] 80 | 81 | 82 | def finalize(self): 83 | tailbytes = self._length & 0x3f 84 | if tailbytes < 56: padding = 55 - tailbytes 85 | else: padding = 119 - tailbytes 86 | self.update(b"\x80" + (b"\0" * padding) + struct.pack("!Q", self._length << 3)) 87 | 88 | 89 | def get_bytes(self): 90 | return struct.pack("!8L", *self.state) 91 | 92 | 93 | @classmethod 94 | def hash(cls, data, finalize = True): 95 | hash = cls() 96 | hash.update(data) 97 | if finalize: hash.finalize() 98 | return hash.get_bytes() 99 | -------------------------------------------------------------------------------- /core/startable.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ############################# 24 | # In-/Deflatable base class # 25 | ############################# 26 | 27 | 28 | 29 | import time 30 | from threading import RLock, Thread 31 | 32 | 33 | 34 | class Startable(object): 35 | 36 | 37 | def __init__(self): 38 | self.start_stop_lock = RLock() 39 | self.started = False 40 | self._reset() 41 | 42 | 43 | def destroy(self): 44 | self.stop() 45 | super(Startable, self).destroy() 46 | 47 | 48 | def _reset(self): 49 | pass 50 | 51 | 52 | def _start(self): 53 | pass 54 | 55 | 56 | def _stop(self): 57 | pass 58 | 59 | 60 | def start(self): 61 | with self.start_stop_lock: 62 | if self.started: return 63 | self._reset() 64 | self._start() 65 | self.started = True 66 | 67 | 68 | def stop(self): 69 | with self.start_stop_lock: 70 | if not self.started: return 71 | self._stop() 72 | self.started = False 73 | 74 | 75 | def restart(self, delay = 0): 76 | time.sleep(delay) 77 | with self.start_stop_lock: 78 | if not self.started: return 79 | self.stop() 80 | self.start() 81 | 82 | 83 | def async_start(self, delay = 0): 84 | Thread(None, self.start, self.settings.name + "_start", (delay,)).start() 85 | 86 | 87 | def async_stop(self, delay = 0): 88 | Thread(None, self.stop, self.settings.name + "_stop", (delay,)).start() 89 | 90 | 91 | def async_restart(self, delay = 0): 92 | Thread(None, self.restart, self.settings.name + "_restart", (delay,)).start() 93 | -------------------------------------------------------------------------------- /core/statistics.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ########################### 24 | # Statistics base classes # 25 | ########################### 26 | 27 | 28 | 29 | from threading import RLock 30 | from .util import Bunch 31 | 32 | 33 | 34 | class Statistics(Bunch): 35 | 36 | 37 | def __init__(self, *args, **kwargs): 38 | super(Statistics, self).__init__(*args, **kwargs) 39 | 40 | 41 | 42 | class StatisticsList(list): 43 | 44 | 45 | def __init__(self, *args, **kwargs): 46 | super(StatisticsList, self).__init__(*args, **kwargs) 47 | 48 | 49 | def calculatefieldsum(self, field): 50 | return sum(element[field] for element in self) 51 | 52 | 53 | def calculatefieldavg(self, field): 54 | if len(self) == 0: return 0 55 | return 1. * sum(element[field] in self) / len(self) 56 | 57 | 58 | 59 | class StatisticsProvider(object): 60 | 61 | 62 | def __init__(self): 63 | self.stats = Bunch() 64 | self.stats.lock = RLock() 65 | self.children = [] 66 | 67 | 68 | def _get_statistics(self, stats, childstats): 69 | stats.obj = self 70 | stats.id = self.id 71 | stats.name = self.settings.name 72 | stats.children = childstats 73 | 74 | 75 | def get_statistics(self): 76 | stats = Statistics() 77 | childstats = StatisticsList() 78 | for child in self.children: childstats.append(child.get_statistics()) 79 | with self.stats.lock: self._get_statistics(stats, childstats) 80 | return stats 81 | -------------------------------------------------------------------------------- /core/util.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ################################# 24 | # Utility classes and functions # 25 | ################################# 26 | 27 | 28 | 29 | class OutputRedirector(object): 30 | 31 | 32 | def __init__(self, core, source, loglevel, flags = ""): 33 | self.core = core 34 | self.source = source 35 | self.loglevel = loglevel 36 | self.flags = flags 37 | 38 | 39 | def write(self, data): 40 | self.core.log(self.source, data, self.loglevel, self.flags) 41 | 42 | 43 | def flush(self): pass 44 | 45 | 46 | 47 | class Bunch(dict): 48 | 49 | 50 | def __init__(self, **kw): 51 | dict.__init__(self, kw) 52 | self.__dict__ = self 53 | 54 | 55 | def __getstate__(self): 56 | return self 57 | 58 | 59 | def __setstate__(self, state): 60 | self.update(state) 61 | self.__dict__ = self 62 | -------------------------------------------------------------------------------- /core/workqueue.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ############## 24 | # Work queue # 25 | ############## 26 | 27 | 28 | 29 | import time 30 | from threading import Condition, RLock, Thread 31 | from .startable import Startable 32 | from .util import Bunch 33 | try: from queue import Queue 34 | except: from Queue import Queue 35 | 36 | 37 | 38 | class WorkQueue(Startable): 39 | 40 | 41 | def __init__(self, core): 42 | self.core = core 43 | self.id = -3 44 | self.settings = Bunch(name = "Work queue") 45 | super(WorkQueue, self).__init__() 46 | # Initialize global work queue lock and wakeup condition 47 | self.lock = Condition() 48 | self.cancelqueue = Queue() 49 | 50 | 51 | def _reset(self): 52 | self.core.event(300, self, "reset", None, "Resetting work queue state") 53 | super(WorkQueue, self)._reset() 54 | # Initialize job list container and count 55 | self.lists = {} 56 | self.target = 5 57 | self.count = 0 58 | self.expirycutoff = 0 59 | # Initialize taken job list container 60 | self.takenlists = {} 61 | 62 | 63 | def add_job(self, job, source = None, subsource = "unknown source"): 64 | if not source: source = self 65 | with self.lock: 66 | if not job.blockchain.check_job(job): 67 | mhashes = job.hashes_remaining / 1000000. 68 | job.worksource.add_pending_mhashes(-mhashes) 69 | job.worksource.add_deferred_mhashes(mhashes) 70 | self.core.log(source, "Discarding one job from %s because it is stale\n" % subsource, 500) 71 | return False 72 | expiry = int(job.expiry) 73 | if not expiry in self.lists: self.lists[expiry] = [job] 74 | else: self.lists[expiry].append(job) 75 | if expiry > self.expirycutoff: self.count += 1 76 | job.register() 77 | self.lock.notify_all() 78 | self.core.log(source, "Got one job from %s\n" % subsource, 500) 79 | return True 80 | 81 | 82 | def add_jobs(self, jobs, source = None, subsource = "unknown source"): 83 | if not source: source = self 84 | with self.lock: 85 | seen = {} 86 | accepted = 0 87 | dropped = 0 88 | for job in jobs: 89 | if not job.blockchain.check_job(job): 90 | dropped += 1 91 | if not job.worksource in seen: 92 | mhashes = 2**32 / 1000000. 93 | job.worksource.add_pending_mhashes(-mhashes) 94 | job.worksource.add_deferred_mhashes(mhashes) 95 | seen[job.worksource] = True 96 | else: 97 | expiry = int(job.expiry) 98 | if not expiry in self.lists: self.lists[expiry] = [job] 99 | else: self.lists[expiry].append(job) 100 | if expiry > self.expirycutoff: self.count += 1 101 | job.register() 102 | accepted += 1 103 | self.lock.notify_all() 104 | if accepted: self.core.log(source, "Got %d jobs from %s\n" % (accepted, subsource), 500) 105 | if dropped: self.core.log(source, "Discarding %d jobs from %s because they are stale\n" % (dropped, subsource), 500) 106 | return accepted 107 | 108 | 109 | def cancel_jobs(self, jobs, graceful = False): 110 | if not jobs: return 111 | self.cancelqueue.put((jobs, graceful)) 112 | 113 | 114 | def remove_job(self, job): 115 | with self.lock: 116 | try: 117 | expiry = int(job.expiry) 118 | try: 119 | self.lists[expiry].remove(job) 120 | if expiry > self.expirycutoff: self.count -= 1 121 | except: pass 122 | try: self.takenlists[expiry].remove(job) 123 | except: pass 124 | except: pass 125 | 126 | 127 | def get_job(self, worker, expiry_min_ahead, async = False): 128 | with self.lock: 129 | while True: 130 | job = self._get_job_internal(expiry_min_ahead) 131 | if job: 132 | job.set_worker(worker) 133 | expiry = int(job.expiry) 134 | if int(job.expiry) <= self.expirycutoff: self.count += 1 135 | if not expiry in self.takenlists: self.takenlists[expiry] = [job] 136 | else: self.takenlists[expiry].append(job) 137 | break 138 | elif async: return None 139 | self.lock.release() 140 | with self.core.fetcher.lock: 141 | self.lock.acquire() 142 | self.core.fetcher.wakeup() 143 | self.lock.wait() 144 | self.core.fetcher.wakeup() 145 | return job 146 | 147 | 148 | def _get_job_internal(self, expiry_min_ahead): 149 | keys = sorted(self.lists.keys()) 150 | min_expiry = time.time() + expiry_min_ahead 151 | # Look for a job that meets min_expiry as closely as possible 152 | for expiry in keys: 153 | if expiry <= min_expiry: continue 154 | list = self.lists[expiry] 155 | if not list: continue 156 | self.count -= 1 157 | return list.pop(0) 158 | # If there was none, look for the job with the latest expiry 159 | keys.reverse() 160 | for expiry in keys: 161 | if expiry > min_expiry: continue 162 | list = self.lists[expiry] 163 | if not list: continue 164 | self.count -= 1 165 | return list.pop(0) 166 | # There were no jobs at all 167 | return None 168 | 169 | 170 | def _start(self): 171 | super(WorkQueue, self)._start() 172 | self.shutdown = False 173 | self.cleanupthread = Thread(None, self._cleanuploop, "workqueue_cleanup") 174 | self.cleanupthread.daemon = True 175 | self.cleanupthread.start() 176 | self.cancelthread = Thread(None, self._cancelloop, "workqueue_cancelworker") 177 | self.cancelthread.daemon = True 178 | self.cancelthread.start() 179 | 180 | 181 | def _stop(self): 182 | self.shutdown = True 183 | self.cleanupthread.join(5) 184 | self.cancelqueue.put(None) 185 | self.cancelthread.join(5) 186 | self._reset() 187 | super(WorkQueue, self)._stop() 188 | 189 | 190 | def _cleanuploop(self): 191 | while not self.shutdown: 192 | now = time.time() 193 | cancel = [] 194 | with self.lock: 195 | keys = sorted(self.lists.keys()) 196 | cutoff = now + 10 197 | for expiry in keys: 198 | if expiry > cutoff: break 199 | if expiry > self.expirycutoff and expiry <= cutoff: self.count -= len(self.lists[expiry]) 200 | if expiry <= now: 201 | while self.lists[expiry]: self.lists[expiry].pop(0).destroy() 202 | del self.lists[expiry] 203 | self.expirycutoff = cutoff 204 | keys = sorted(self.takenlists.keys()) 205 | for expiry in keys: 206 | if expiry <= now: 207 | while self.takenlists[expiry]: cancel.append(self.takenlists[expiry].pop(0)) 208 | del self.takenlists[expiry] 209 | self.core.fetcher.wakeup() 210 | self.cancel_jobs(cancel) 211 | time.sleep(1) 212 | 213 | 214 | def _cancelloop(self): 215 | while True: 216 | data = self.cancelqueue.get() 217 | if not data: return 218 | jobs, graceful = data 219 | for job in jobs: 220 | try: job.cancel(graceful) 221 | except: self.core.log(self.core, "Error while canceling job: %s\n" % traceback.format_exc(), 100, "r") 222 | -------------------------------------------------------------------------------- /modules/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSeven/Modular-Python-Bitcoin-Miner/4d3ac96712678191a065a01745fb1ae00610b7df/modules/__init__.py -------------------------------------------------------------------------------- /modules/fpgamining/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSeven/Modular-Python-Bitcoin-Miner/4d3ac96712678191a065a01745fb1ae00610b7df/modules/fpgamining/__init__.py -------------------------------------------------------------------------------- /modules/fpgamining/x6500/__init__.py: -------------------------------------------------------------------------------- 1 | from .x6500worker import X6500Worker 2 | from .x6500hotplug import X6500HotplugWorker 3 | 4 | workerclasses = [X6500Worker, X6500HotplugWorker] 5 | -------------------------------------------------------------------------------- /modules/fpgamining/x6500/util/BitstreamReader.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011 by fpgaminer 2 | # fizzisist 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in 12 | # all copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | # THE SOFTWARE. 21 | 22 | # Parse a .BIT file generated by Xilinx's bitgen. 23 | # That is the default file generated during ISE's compilation. 24 | # 25 | # FILE FORMAT: 26 | # 27 | # Consists of an initial 11 bytes of unknown content (???) 28 | # Then 5 fields of the format: 29 | # 1 byte key 30 | # 2 byte, Big Endian Length (EXCEPT: The last field, which has a 4 byte length) 31 | # data (of length specified above ^) 32 | # 33 | # The 5 fields have keys in the sequence a, b, c, d, e 34 | # The data from the first 4 fields are strings: 35 | # design name, part name, date, time 36 | # The last field is the raw bitstream. 37 | # 38 | 39 | import time 40 | import struct 41 | 42 | # Dictionary for looking up idcodes from device names: 43 | idcode_lut = {'6slx150fgg484': 0x401d093, '6slx45csg324': 0x4008093, '6slx150tfgg676': 0x403D093} 44 | 45 | class BitFileReadError(Exception): 46 | _corruptFileMessage = "Unable to parse .bit file; header is malformed. Is it really a Xilinx .bit file?" 47 | 48 | def __init__(self, value=None): 49 | self.parameter = BitFileReadError._corruptFileMessage if value is None else value 50 | def __str__(self): 51 | return repr(self.parameter) 52 | 53 | class BitFileMismatch(Exception): 54 | _mismatchMessage = "Device IDCode does not match bitfile IDCode! Was this bitstream built for this FPGA?" 55 | 56 | def __init__(self, value=None): 57 | self.parameter = BitFileReadError._mismatchMessage if value is None else value 58 | def __str__(self): 59 | return repr(self.parameter) 60 | 61 | class BitFileUnknown(Exception): 62 | _unknownMessage = "Bitfile has an unknown UserID! Was this bitstream built for the X6500?" 63 | def __init__(self, value=None): 64 | self.parameter = BitFileReadError._unknownMessage if value is None else value 65 | def __str__(self): 66 | return repr(self.parameter) 67 | 68 | class Object(object): 69 | pass 70 | 71 | class BitFile: 72 | """Read a .bit file and return a BitFile object.""" 73 | @staticmethod 74 | def read(name): 75 | with open(name, 'rb') as f: 76 | bitfile = BitFile() 77 | 78 | # 11 bytes of unknown data 79 | if BitFile._readLength(f) != 9: 80 | raise BitFileReadError() 81 | 82 | BitFile._readOrDie(f, 11) 83 | 84 | bitfile.designname = BitFile._readField(f, b"a").decode("latin1").rstrip('\0') 85 | bitfile.userid = int(bitfile.designname.split(';')[-1].split('=')[-1], base=16) 86 | bitfile.part = BitFile._readField(f, b"b").decode("latin1").rstrip('\0') 87 | bitfile.date = BitFile._readField(f, b"c").decode("latin1").rstrip('\0') 88 | bitfile.time = BitFile._readField(f, b"d").decode("latin1").rstrip('\0') 89 | bitfile.idcode = idcode_lut[bitfile.part] 90 | 91 | if bitfile.userid == 0xFFFFFFFF: 92 | bitfile.rev = 0 93 | bitfile.build = 0 94 | elif (bitfile.userid >> 16) & 0xFFFF == 0x4224: 95 | bitfile.rev = (bitfile.userid >> 8) & 0xFF 96 | bitfile.build = bitfile.userid & 0xFF 97 | else: 98 | raise BitFileUnknown() 99 | 100 | if BitFile._readOrDie(f, 1) != b"e": 101 | raise BitFileReadError() 102 | 103 | length = BitFile._readLength4(f) 104 | bitfile.bitstream = BitFile._readOrDie(f, length) 105 | 106 | return bitfile 107 | 108 | # Read a 2-byte, unsigned, Big Endian length. 109 | @staticmethod 110 | def _readLength(filestream): 111 | return struct.unpack(">H", BitFile._readOrDie(filestream, 2))[0] 112 | 113 | @staticmethod 114 | def _readLength4(filestream): 115 | return struct.unpack(">I", BitFile._readOrDie(filestream, 4))[0] 116 | 117 | # Read length bytes, or throw an exception 118 | @staticmethod 119 | def _readOrDie(filestream, length): 120 | data = filestream.read(length) 121 | 122 | if len(data) < length: 123 | raise BitFileReadError() 124 | 125 | return data 126 | 127 | @staticmethod 128 | def _readField(filestream, key): 129 | if BitFile._readOrDie(filestream, 1) != key: 130 | raise BitFileReadError() 131 | 132 | length = BitFile._readLength(filestream) 133 | data = BitFile._readOrDie(filestream, length) 134 | 135 | return data 136 | 137 | 138 | def __init__(self): 139 | self.designname = None 140 | self.rev = None 141 | self.build = None 142 | self.part = None 143 | self.date = None 144 | self.time = None 145 | self.length = None 146 | self.idcode = None 147 | self.bitstream = None 148 | 149 | -------------------------------------------------------------------------------- /modules/fpgamining/x6500/util/TAP.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011 by fpgaminer 2 | # fizzisist 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in 12 | # all copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | # THE SOFTWARE. 21 | 22 | class TAPStateError(Exception): 23 | def __init__(self, current, destination): 24 | self.current = TAP.STR_TRANSLATE[current] 25 | self.destination = TAP.STR_TRANSLATE[destination] 26 | def __str__(self): 27 | return self.current + " -> " + self.destination 28 | 29 | class TAP: 30 | TLR = 0 31 | IDLE = 1 32 | SELECT_DR = 2 33 | CAPTURE_DR = 3 34 | SHIFT_DR = 4 35 | EXIT1_DR = 5 36 | PAUSE_DR = 6 37 | EXIT2_DR = 7 38 | UPDATE_DR = 8 39 | SELECT_IR = 9 40 | CAPTURE_IR = 10 41 | SHIFT_IR = 11 42 | EXIT1_IR = 12 43 | PAUSE_IR = 13 44 | EXIT2_IR = 14 45 | UPDATE_IR = 15 46 | 47 | STR_TRANSLATE = ['TLR','IDLE','SELECT_DR','CAPTURE_DR','SHIFT_DR','EXIT1_DR','PAUSE_DR','EXIT2_DR','UPDATE_DR','SELECT_IR','CAPTURE_IR','SHIFT_IR','EXIT1_IR','PAUSE_IR','EXIT2_IR','UPDATE_IR'] 48 | 49 | TRANSITIONS = { 50 | TLR: [IDLE, TLR], 51 | IDLE: [IDLE, SELECT_DR], 52 | SELECT_DR: [CAPTURE_DR, SELECT_IR], 53 | CAPTURE_DR: [SHIFT_DR, EXIT1_DR], 54 | SHIFT_DR: [SHIFT_DR, EXIT1_DR], 55 | EXIT1_DR: [PAUSE_DR, UPDATE_DR], 56 | PAUSE_DR: [PAUSE_DR, EXIT2_DR], 57 | EXIT2_DR: [SHIFT_DR, UPDATE_DR], 58 | UPDATE_DR: [IDLE, SELECT_DR], 59 | SELECT_IR: [CAPTURE_IR, TLR], 60 | CAPTURE_IR: [SHIFT_IR, EXIT1_IR], 61 | SHIFT_IR: [SHIFT_IR, EXIT1_IR], 62 | EXIT1_IR: [PAUSE_IR, UPDATE_IR], 63 | PAUSE_IR: [PAUSE_IR, EXIT2_IR], 64 | EXIT2_IR: [SHIFT_IR, UPDATE_IR], 65 | UPDATE_IR: [IDLE, SELECT_DR] 66 | } 67 | 68 | def __init__(self, jtagClock): 69 | self.jtagClock = jtagClock 70 | self.state = None 71 | 72 | def reset(self): 73 | for i in range(6): 74 | self.jtagClock(tms=1) 75 | 76 | self.state = TAP.TLR 77 | 78 | def clocked(self, tms): 79 | if self.state is None: 80 | return 81 | 82 | state = self.state 83 | self.state = TAP.TRANSITIONS[self.state][tms] 84 | 85 | 86 | # When goto is called, we look at where we want to go and where we are. 87 | # Based on that we choose where to clock TMS low or high. 88 | # After that we see if we've reached our goal. If not, call goto again. 89 | # This recursive behavior keeps the function simple. 90 | def goto(self, state): 91 | # If state is Unknown, reset. 92 | if self.state is None: 93 | self.reset() 94 | elif state == TAP.TLR: 95 | self.jtagClock(tms=1) 96 | elif self.state == TAP.TLR: 97 | self.jtagClock(tms=0) 98 | elif state == TAP.SELECT_DR: 99 | if self.state != TAP.IDLE: 100 | raise TAPStateError(self.state, state) 101 | 102 | self.jtagClock(tms=1) 103 | elif state == TAP.SELECT_IR: 104 | if self.state != TAP.IDLE: 105 | raise TAPStateError(self.state, state) 106 | 107 | self.jtagClock(tms=1) 108 | self.jtagClock(tms=1) 109 | elif state == TAP.SHIFT_DR: 110 | if self.state != TAP.SELECT_DR: 111 | raise TAPStateError(self.state, state) 112 | 113 | self.jtagClock(tms=0) 114 | self.jtagClock(tms=0) 115 | elif state == TAP.SHIFT_IR: 116 | if self.state != TAP.SELECT_IR: 117 | raise TAPStateError(self.state, state) 118 | 119 | self.jtagClock(tms=0) 120 | self.jtagClock(tms=0) 121 | elif state == TAP.IDLE: 122 | if self.state == TAP.IDLE: 123 | self.jtagClock(tms=0) 124 | elif self.state == TAP.EXIT1_DR or self.state == TAP.EXIT1_IR: 125 | self.jtagClock(tms=1) 126 | self.jtagClock(tms=0) 127 | else: 128 | raise TAPStateError(self.state, state) 129 | else: 130 | raise TAPStateError(self.state, state) 131 | 132 | 133 | if self.state != state: 134 | self.goto(state) 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /modules/fpgamining/x6500/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSeven/Modular-Python-Bitcoin-Miner/4d3ac96712678191a065a01745fb1ae00610b7df/modules/fpgamining/x6500/util/__init__.py -------------------------------------------------------------------------------- /modules/fpgamining/x6500/util/format.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Copyright (C) 2011 by jedi95 and 4 | # CFSworks 5 | # fizzisist 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in 15 | # all copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | # THE SOFTWARE. 24 | 25 | def formatNumber(n): 26 | """Format a positive integer in a more readable fashion.""" 27 | if n < 0: 28 | raise ValueError('can only format positive integers') 29 | prefixes = 'kMGTP' 30 | whole = str(int(n)) 31 | decimal = '' 32 | i = 0 33 | while len(whole) > 3: 34 | if i + 1 < len(prefixes): 35 | decimal = '.%s' % whole[-3:-1] 36 | whole = whole[:-3] 37 | i += 1 38 | else: 39 | break 40 | return '%s%s %s' % (whole, decimal, prefixes[i]) 41 | 42 | def formatTime(seconds): 43 | """Take a number of seconds and turn it into a string like 32m18s""" 44 | minutes = int(seconds / 60) 45 | hours = int(minutes / 60) 46 | days = int(hours / 24) 47 | weeks = int(days / 7) 48 | seconds = seconds % 60 49 | minutes = minutes % 60 50 | hours = hours % 24 51 | days = days % 7 52 | 53 | time_string = '' 54 | if weeks > 0: 55 | time_string += '%dw' % weeks 56 | if days > 0: 57 | time_string += '%dd' % days 58 | if hours > 0: 59 | time_string += '%dh' % hours 60 | if minutes > 0: 61 | time_string += '%dm' % minutes 62 | if hours < 1: 63 | # hide the seconds when we're over an hour 64 | time_string += '%ds' % seconds 65 | 66 | return time_string 67 | -------------------------------------------------------------------------------- /modules/theseven/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSeven/Modular-Python-Bitcoin-Miner/4d3ac96712678191a065a01745fb1ae00610b7df/modules/theseven/__init__.py -------------------------------------------------------------------------------- /modules/theseven/basicloggers/__init__.py: -------------------------------------------------------------------------------- 1 | from .stderrlogger import StderrLogger 2 | from .logfilelogger import LogFileLogger 3 | 4 | frontendclasses = [StderrLogger, LogFileLogger] 5 | -------------------------------------------------------------------------------- /modules/theseven/basicloggers/logfilelogger.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ########################## 24 | # Simple log file logger # 25 | ########################## 26 | 27 | 28 | 29 | import os 30 | from threading import RLock 31 | from core.basefrontend import BaseFrontend 32 | 33 | 34 | 35 | class LogFileLogger(BaseFrontend): 36 | 37 | version = "theseven.basicloggers log file logger v0.1.0" 38 | default_name = "Untitled log file logger" 39 | can_log = True 40 | can_autodetect = False 41 | settings = dict(BaseFrontend.settings, **{ 42 | "filename": {"title": "Log file name", "type": "string", "position": 1000}, 43 | "loglevel": {"title": "Log level", "type": "int", "position": 2000}, 44 | "useansi": {"title": "Use ANSI codes", "type": "boolean", "position": 3000}, 45 | }) 46 | 47 | 48 | def __init__(self, core, state = None): 49 | super(LogFileLogger, self).__init__(core, state) 50 | 51 | 52 | def apply_settings(self): 53 | super(LogFileLogger, self).apply_settings() 54 | if not "filename" in self.settings or not self.settings.filename: self.settings.filename = "mpbm.log" 55 | if not "loglevel" in self.settings: self.settings.loglevel = self.core.default_loglevel 56 | if not "useansi" in self.settings: self.settings.useansi = False 57 | if self.started and self.settings.filename != self.filename: self.async_restart() 58 | 59 | 60 | def _start(self): 61 | super(LogFileLogger, self)._start() 62 | self.filename = self.settings.filename 63 | self.handle = open(self.filename, "ab") 64 | self.handle.write(("\n" + "=" * 200 + "\n\n").encode("utf_8")) 65 | 66 | 67 | def _stop(self): 68 | self.handle.close() 69 | super(LogFileLogger, self)._stop() 70 | 71 | 72 | def write_log_message(self, source, timestamp, loglevel, messages): 73 | if not self.started: return 74 | if loglevel > self.settings.loglevel: return 75 | prefix = "%s [%3d] %s: " % (timestamp.strftime("%Y-%m-%d %H:%M:%S.%f"), loglevel, source.settings.name) 76 | newline = True 77 | for message, format in messages: 78 | for line in message.splitlines(True): 79 | if self.settings.useansi: 80 | modes = "" 81 | if "r" in format: modes += ";31" 82 | elif "y" in format: modes += ";33" 83 | elif "g" in format: modes += ";32" 84 | if "B" in format: modes += ";1" 85 | if modes: line = "\x1b[0%sm%s\x1b[0m" % (modes, line) 86 | self.handle.write((prefix + line if newline else line).encode("utf_8")) 87 | newline = line[-1:] == "\n" 88 | -------------------------------------------------------------------------------- /modules/theseven/basicloggers/stderrlogger.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ######################## 24 | # Simple stderr logger # 25 | ######################## 26 | 27 | 28 | 29 | import os 30 | from threading import RLock 31 | from core.basefrontend import BaseFrontend 32 | 33 | 34 | 35 | class StderrLogger(BaseFrontend): 36 | 37 | version = "theseven.basicloggers stderr logger v0.1.0" 38 | default_name = "stderr logger" 39 | can_log = True 40 | can_autodetect = True 41 | settings = dict(BaseFrontend.settings, **{ 42 | "loglevel": {"title": "Log level", "type": "int", "position": 1000}, 43 | "useansi": {"title": "Use ANSI codes", "type": "boolean", "position": 2000}, 44 | }) 45 | 46 | 47 | @classmethod 48 | def autodetect(self, core): 49 | core.add_frontend(self(core)) 50 | 51 | 52 | def __init__(self, core, state = None): 53 | super(StderrLogger, self).__init__(core, state) 54 | 55 | 56 | def apply_settings(self): 57 | super(StderrLogger, self).apply_settings() 58 | if not "loglevel" in self.settings: self.settings.loglevel = self.core.default_loglevel 59 | if not "useansi" in self.settings: self.settings.useansi = "TERM" in os.environ 60 | 61 | 62 | def _start(self): 63 | super(StderrLogger, self)._start() 64 | 65 | # Clear screen 66 | if self.settings.useansi: self.core.stderr.write("\x1b[2J") 67 | else: self.core.stderr.write("\n" * 100) 68 | 69 | 70 | def write_log_message(self, source, timestamp, loglevel, messages): 71 | if not self.started: return 72 | if loglevel > self.settings.loglevel: return 73 | prefix = "%s [%3d] %s: " % (timestamp.strftime("%Y-%m-%d %H:%M:%S.%f"), loglevel, source.settings.name) 74 | newline = True 75 | for message, format in messages: 76 | for line in message.splitlines(True): 77 | if self.settings.useansi: 78 | modes = "" 79 | if "r" in format: modes += ";31" 80 | elif "y" in format: modes += ";33" 81 | elif "g" in format: modes += ";32" 82 | if "B" in format: modes += ";1" 83 | if modes: line = "\x1b[0%sm%s\x1b[0m" % (modes, line) 84 | self.core.stderr.write(prefix + line if newline else line) 85 | newline = line[-1:] == "\n" 86 | -------------------------------------------------------------------------------- /modules/theseven/bcjsonrpc/__init__.py: -------------------------------------------------------------------------------- 1 | from .bcjsonrpcworksource import BCJSONRPCWorkSource 2 | 3 | worksourceclasses = [BCJSONRPCWorkSource] 4 | -------------------------------------------------------------------------------- /modules/theseven/bflsingle/__init__.py: -------------------------------------------------------------------------------- 1 | from .bflsingleworker import BFLSingleWorker 2 | from .bflsinglehotplug import BFLSingleHotplugWorker 3 | 4 | workerclasses = [BFLSingleWorker, BFLSingleHotplugWorker] 5 | -------------------------------------------------------------------------------- /modules/theseven/bflsingle/bflsinglehotplug.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2011-2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ################################################################# 24 | # Butterfly Labs Inc. BitFORCE Single hotplug controller module # 25 | ################################################################# 26 | 27 | 28 | 29 | import traceback 30 | from glob import glob 31 | from threading import Condition, Thread 32 | from core.baseworker import BaseWorker 33 | from .bflsingleworker import BFLSingleWorker 34 | 35 | 36 | 37 | # Worker main class, referenced from __init__.py 38 | class BFLSingleHotplugWorker(BaseWorker): 39 | 40 | version = "theseven.bflsingle hotplug manager v0.1.0" 41 | default_name = "BFL Single hotplug manager" 42 | can_autodetect = True 43 | settings = dict(BaseWorker.settings, **{ 44 | "scaninterval": {"title": "Bus scan interval", "type": "float", "position": 2200}, 45 | }) 46 | 47 | 48 | @classmethod 49 | def autodetect(self, core): 50 | try: 51 | import serial 52 | found = False 53 | for port in glob("/dev/serial/by-id/usb-Butterfly_Labs_Inc._BitFORCE_SHA256-*"): 54 | try: 55 | handle = serial.Serial(port, 115200, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_ONE, 1, False, False, 5, False, None) 56 | handle.close() 57 | found = True 58 | break 59 | except: pass 60 | if found: core.add_worker(self(core)) 61 | except: pass 62 | 63 | 64 | # Constructor, gets passed a reference to the miner core and the saved worker state, if present 65 | def __init__(self, core, state = None): 66 | # Initialize bus scanner wakeup event 67 | self.wakeup = Condition() 68 | 69 | # Let our superclass do some basic initialization and restore the state if neccessary 70 | super(BFLSingleHotplugWorker, self).__init__(core, state) 71 | 72 | 73 | # Validate settings, filling them with default values if neccessary. 74 | # Called from the constructor and after every settings change. 75 | def apply_settings(self): 76 | # Let our superclass handle everything that isn't specific to this worker module 77 | super(BFLSingleHotplugWorker, self).apply_settings() 78 | if not "scaninterval" in self.settings or not self.settings.scaninterval: self.settings.scaninterval = 10 79 | # Rescan the bus immediately to apply the new settings 80 | with self.wakeup: self.wakeup.notify() 81 | 82 | 83 | # Reset our state. Called both from the constructor and from self.start(). 84 | def _reset(self): 85 | # Let our superclass handle everything that isn't specific to this worker module 86 | super(BFLSingleHotplugWorker, self)._reset() 87 | # These need to be set here in order to make the equality check in apply_settings() happy, 88 | # when it is run before starting the module for the first time. (It is called from the constructor.) 89 | 90 | 91 | # Start up the worker module. This is protected against multiple calls and concurrency by a wrapper. 92 | def _start(self): 93 | # Let our superclass handle everything that isn't specific to this worker module 94 | super(BFLSingleHotplugWorker, self)._start() 95 | # Initialize child map 96 | self.childmap = {} 97 | # Reset the shutdown flag for our threads 98 | self.shutdown = False 99 | # Start up the main thread, which handles pushing work to the device. 100 | self.mainthread = Thread(None, self.main, self.settings.name + "_main") 101 | self.mainthread.daemon = True 102 | self.mainthread.start() 103 | 104 | 105 | # Shut down the worker module. This is protected against multiple calls and concurrency by a wrapper. 106 | def _stop(self): 107 | # Let our superclass handle everything that isn't specific to this worker module 108 | super(BFLSingleHotplugWorker, self)._stop() 109 | # Set the shutdown flag for our threads, making them terminate ASAP. 110 | self.shutdown = True 111 | # Trigger the main thread's wakeup flag, to make it actually look at the shutdown flag. 112 | with self.wakeup: self.wakeup.notify() 113 | # Wait for the main thread to terminate. 114 | self.mainthread.join(10) 115 | # Shut down child workers 116 | while self.children: 117 | child = self.children.pop(0) 118 | try: 119 | self.core.log(self, "Shutting down worker %s...\n" % (child.settings.name), 800) 120 | child.stop() 121 | except Exception as e: 122 | self.core.log(self, "Could not stop worker %s: %s\n" % (child.settings.name, traceback.format_exc()), 100, "rB") 123 | 124 | 125 | # Main thread entry point 126 | # This thread is responsible for scanning for boards and spawning worker modules for them 127 | def main(self): 128 | import serial 129 | number = 0 130 | 131 | # Loop until we are shut down 132 | while not self.shutdown: 133 | 134 | try: 135 | boards = {} 136 | for port in glob("/dev/serial/by-id/usb-Butterfly_Labs_Inc._BitFORCE_SHA256-*"): 137 | available = False 138 | try: 139 | handle = serial.Serial(port, 115200, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_ONE, 1, False, False, 5, False, None) 140 | handle.close() 141 | available = True 142 | except: pass 143 | boards[port] = available 144 | 145 | kill = [] 146 | for port, child in self.childmap.items(): 147 | if not port in boards: 148 | kill.append((port, child)) 149 | 150 | for port, child in kill: 151 | try: 152 | self.core.log(self, "Shutting down worker %s...\n" % (child.settings.name), 800) 153 | child.stop() 154 | except Exception as e: 155 | self.core.log(self, "Could not stop worker %s: %s\n" % (child.settings.name, traceback.format_exc()), 100, "rB") 156 | childstats = child.get_statistics() 157 | fields = ["ghashes", "jobsaccepted", "jobscanceled", "sharesaccepted", "sharesrejected", "sharesinvalid"] 158 | for field in fields: self.stats[field] += childstats[field] 159 | try: self.child.destroy() 160 | except: pass 161 | del self.childmap[port] 162 | try: self.children.remove(child) 163 | except: pass 164 | 165 | for port, available in boards.items(): 166 | if port in self.childmap or not available: continue 167 | number += 1 168 | child = BFLSingleWorker(self.core) 169 | child.settings.name = "Autodetected BFL Single %d" % number 170 | child.settings.port = port 171 | child.apply_settings() 172 | self.childmap[port] = child 173 | self.children.append(child) 174 | try: 175 | self.core.log(self, "Starting up worker %s...\n" % (child.settings.name), 800) 176 | child.start() 177 | except Exception as e: 178 | self.core.log(self, "Could not start worker %s: %s\n" % (child.settings.name, traceback.format_exc()), 100, "rB") 179 | 180 | except: self.core.log(self, "Caught exception: %s\n" % traceback.format_exc(), 100, "rB") 181 | 182 | with self.wakeup: self.wakeup.wait(self.settings.scaninterval) 183 | -------------------------------------------------------------------------------- /modules/theseven/cairnsmore/__init__.py: -------------------------------------------------------------------------------- 1 | from .cairnsmoreworker import CairnsmoreWorker 2 | from .cairnsmorehotplug import CairnsmoreHotplugWorker 3 | 4 | workerclasses = [CairnsmoreWorker, CairnsmoreHotplugWorker] 5 | -------------------------------------------------------------------------------- /modules/theseven/ftdijtag/__init__.py: -------------------------------------------------------------------------------- 1 | from .ftdijtagworker import FTDIJTAGWorker 2 | from .ftdijtaghotplug import FTDIJTAGHotplugWorker 3 | 4 | workerclasses = [FTDIJTAGWorker, FTDIJTAGHotplugWorker] 5 | -------------------------------------------------------------------------------- /modules/theseven/ftdijtag/boardproxy.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ############################################################################## 24 | # Generic FTDI JTAG bitbanging worker out of process board access dispatcher # 25 | ############################################################################## 26 | 27 | 28 | 29 | import time 30 | import signal 31 | import traceback 32 | from threading import Thread, Condition, RLock 33 | from multiprocessing import Process 34 | from .driver import FTDIJTAGDevice 35 | 36 | 37 | 38 | class FTDIJTAGBoardProxy(Process): 39 | 40 | 41 | def __init__(self, rxconn, txconn, serial, takeover, firmware, pollinterval): 42 | super(FTDIJTAGBoardProxy, self).__init__() 43 | self.rxconn = rxconn 44 | self.txconn = txconn 45 | self.serial = serial 46 | self.takeover = takeover 47 | self.firmware = firmware 48 | self.pollinterval = pollinterval 49 | 50 | 51 | def run(self): 52 | signal.signal(signal.SIGINT, signal.SIG_IGN) 53 | signal.signal(signal.SIGTERM, signal.SIG_IGN) 54 | self.lock = RLock() 55 | self.wakeup = Condition() 56 | self.error = None 57 | self.pollingthread = None 58 | self.shutdown = False 59 | 60 | try: 61 | 62 | # Listen for setup commands 63 | while True: 64 | data = self.rxconn.recv() 65 | 66 | if data[0] == "connect": break 67 | 68 | else: raise Exception("Unknown setup message: %s" % str(data)) 69 | 70 | # Connect to board 71 | self.device = FTDIJTAGDevice(self, self.serial, self.takeover, self.firmware) 72 | self.fpgacount = self.device.get_fpga_count() 73 | self.log("Found %i FPGA%s\n" % (self.fpgacount, 's' if self.fpgacount != 1 else ''), 500) 74 | if not self.fpgacount: raise Exception("No FPGAs detected!") 75 | 76 | # Drain leftover nonces 77 | while True: 78 | nonces = self.device.read_nonces() 79 | if not nonces: break 80 | 81 | # Start polling thread 82 | self.pollingthread = Thread(None, self.polling_thread, "polling_thread") 83 | self.pollingthread.daemon = True 84 | self.pollingthread.start() 85 | 86 | self.send("started_up", self.fpgacount) 87 | 88 | # Listen for commands 89 | while True: 90 | if self.error: raise self.error 91 | 92 | data = self.rxconn.recv() 93 | 94 | if data[0] == "shutdown": break 95 | 96 | elif data[0] == "ping": self.send("pong") 97 | 98 | elif data[0] == "pong": pass 99 | 100 | elif data[0] == "set_pollinterval": 101 | self.pollinterval = data[1] 102 | with self.wakeup: self.wakeup.notify() 103 | 104 | elif data[0] == "send_job": 105 | start = time.time() 106 | self.device.send_job(data[1], data[2]) 107 | end = time.time() 108 | self.respond(start, end) 109 | 110 | elif data[0] == "set_speed": 111 | self.device.set_speed(data[1], data[2]) 112 | 113 | elif data[0] == "get_speed": 114 | self.respond(self.device.get_speed(data[1])) 115 | 116 | else: raise Exception("Unknown message: %s" % str(data)) 117 | 118 | except: self.log("Exception caught: %s" % traceback.format_exc(), 100, "r") 119 | finally: 120 | self.shutdown = True 121 | with self.wakeup: self.wakeup.notify() 122 | try: self.pollingthread.join(2) 123 | except: pass 124 | self.send("dying") 125 | 126 | 127 | def send(self, *args): 128 | with self.lock: self.txconn.send(args) 129 | 130 | 131 | def respond(self, *args): 132 | self.send("response", *args) 133 | 134 | 135 | def log(self, message, loglevel, format = ""): 136 | self.send("log", message, loglevel, format) 137 | 138 | 139 | def polling_thread(self): 140 | try: 141 | counter = 0 142 | while not self.shutdown: 143 | # Poll for nonces 144 | nonces = self.device.read_nonces() 145 | for fpga in nonces: self.send("nonce_found", fpga, time.time(), nonces[fpga]) 146 | 147 | counter += 1 148 | if counter >= 20: 149 | counter = 0 150 | self.send("temperatures_read", self.device.read_temperatures()) 151 | 152 | with self.wakeup: self.wakeup.wait(self.pollinterval) 153 | 154 | except Exception as e: 155 | self.log("Exception caught: %s" % traceback.format_exc(), 100, "r") 156 | self.error = e 157 | # Unblock main thread 158 | self.send("ping") 159 | -------------------------------------------------------------------------------- /modules/theseven/icarus/__init__.py: -------------------------------------------------------------------------------- 1 | from .icarusworker import IcarusWorker 2 | 3 | workerclasses = [IcarusWorker] 4 | -------------------------------------------------------------------------------- /modules/theseven/mmq/__init__.py: -------------------------------------------------------------------------------- 1 | from .mmqworker import MMQWorker 2 | from .mmqhotplug import MMQHotplugWorker 3 | 4 | workerclasses = [MMQWorker, MMQHotplugWorker] 5 | -------------------------------------------------------------------------------- /modules/theseven/mmq/boardproxy.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ############################################################### 24 | # ModMiner Quad worker out of process board access dispatcher # 25 | ############################################################### 26 | 27 | 28 | 29 | import time 30 | import signal 31 | import traceback 32 | from threading import RLock, Thread, Condition 33 | from multiprocessing import Process 34 | from .driver import MMQDevice 35 | 36 | 37 | 38 | class MMQBoardProxy(Process): 39 | 40 | 41 | def __init__(self, rxconn, txconn, port, firmware, pollinterval): 42 | super(MMQBoardProxy, self).__init__() 43 | self.rxconn = rxconn 44 | self.txconn = txconn 45 | self.port = port 46 | self.firmware = firmware 47 | self.pollinterval = pollinterval 48 | 49 | 50 | def run(self): 51 | signal.signal(signal.SIGINT, signal.SIG_IGN) 52 | signal.signal(signal.SIGTERM, signal.SIG_IGN) 53 | self.lock = RLock() 54 | self.wakeup = Condition() 55 | self.error = None 56 | self.pollingthread = None 57 | self.shutdown = False 58 | 59 | try: 60 | 61 | # Listen for setup commands 62 | while True: 63 | data = self.rxconn.recv() 64 | 65 | if data[0] == "connect": break 66 | 67 | else: raise Exception("Unknown setup message: %s" % str(data)) 68 | 69 | # Connect to board 70 | self.device = MMQDevice(self, self.port, self.firmware) 71 | self.fpgacount = self.device.get_fpga_count() 72 | self.log("Found %i FPGA%s\n" % (self.fpgacount, 's' if self.fpgacount != 1 else ''), 500) 73 | if not self.fpgacount: raise Exception("No FPGAs detected!") 74 | 75 | # Start polling thread 76 | self.pollingthread = Thread(None, self.polling_thread, "polling_thread") 77 | self.pollingthread.daemon = True 78 | self.pollingthread.start() 79 | 80 | self.send("started_up", self.fpgacount) 81 | 82 | # Listen for commands 83 | while True: 84 | if self.error: raise self.error 85 | 86 | data = self.rxconn.recv() 87 | 88 | if data[0] == "shutdown": break 89 | 90 | elif data[0] == "ping": self.send("pong") 91 | 92 | elif data[0] == "pong": pass 93 | 94 | elif data[0] == "set_pollinterval": 95 | self.pollinterval = data[1] 96 | with self.wakeup: self.wakeup.notify() 97 | 98 | elif data[0] == "send_job": 99 | start = time.time() 100 | self.device.send_job(data[1], data[2]) 101 | end = time.time() 102 | self.respond(start, end) 103 | 104 | elif data[0] == "read_reg": 105 | self.respond(self.device.read_reg(data[1], data[2])) 106 | 107 | elif data[0] == "write_reg": 108 | self.device.write_reg(data[1], data[2], data[3]) 109 | 110 | elif data[0] == "set_speed": 111 | self.device.set_speed(data[1], data[2]) 112 | 113 | elif data[0] == "get_speed": 114 | self.respond(self.device.get_speed(data[1])) 115 | 116 | else: raise Exception("Unknown message: %s" % str(data)) 117 | 118 | except: self.log("Exception caught: %s" % traceback.format_exc(), 100, "r") 119 | finally: 120 | self.shutdown = True 121 | with self.wakeup: self.wakeup.notify() 122 | try: self.pollingthread.join(2) 123 | except: pass 124 | try: self.device.close() 125 | except: pass 126 | self.send("dying") 127 | 128 | 129 | def send(self, *args): 130 | with self.lock: self.txconn.send(args) 131 | 132 | 133 | def respond(self, *args): 134 | self.send("response", *args) 135 | 136 | 137 | def log(self, message, loglevel, format = ""): 138 | self.send("log", message, loglevel, format) 139 | 140 | 141 | def nonce_found(self, fpga, nonce): 142 | self.send("nonce_found", fpga, time.time(), nonce) 143 | 144 | 145 | def temperatures_read(self, temperatures): 146 | self.send("temperatures_read", temperatures) 147 | 148 | 149 | def error(self, exception): 150 | self.error = exception 151 | self.send("ping") 152 | 153 | 154 | def polling_thread(self): 155 | try: 156 | counter = 0 157 | while not self.shutdown: 158 | # Poll for nonces 159 | nonces = self.device.read_nonces() 160 | for fpga in nonces: self.nonce_found(fpga, nonces[fpga]) 161 | 162 | counter += 1 163 | if counter >= 20: 164 | counter = 0 165 | self.temperatures_read(self.device.read_temperatures()) 166 | 167 | with self.wakeup: self.wakeup.wait(self.pollinterval) 168 | 169 | except Exception as e: 170 | self.log("Exception caught: %s" % traceback.format_exc(), 100, "r") 171 | self.error = e 172 | # Unblock main thread 173 | self.send("ping") 174 | -------------------------------------------------------------------------------- /modules/theseven/simplers232/__init__.py: -------------------------------------------------------------------------------- 1 | from .simplers232worker import SimpleRS232Worker 2 | 3 | workerclasses = [SimpleRS232Worker] 4 | -------------------------------------------------------------------------------- /modules/theseven/sqlite/__init__.py: -------------------------------------------------------------------------------- 1 | from .sqlitestats import SQLiteStats 2 | 3 | frontendclasses = [SQLiteStats] 4 | -------------------------------------------------------------------------------- /modules/theseven/stratum/__init__.py: -------------------------------------------------------------------------------- 1 | from .stratumworksource import StratumWorkSource 2 | 3 | worksourceclasses = [StratumWorkSource] 4 | -------------------------------------------------------------------------------- /modules/theseven/webui/__init__.py: -------------------------------------------------------------------------------- 1 | from .webui import WebUI 2 | 3 | frontendclasses = [WebUI] 4 | -------------------------------------------------------------------------------- /modules/theseven/webui/api/__init__.py: -------------------------------------------------------------------------------- 1 | from . import init 2 | from . import gadgethost 3 | from . import menugadget 4 | from . import statsgadget 5 | from . import log 6 | from . import uiconfig 7 | from . import frontendeditor 8 | from . import workereditor 9 | from . import worksourceeditor 10 | from . import blockchaineditor 11 | from . import settingseditor 12 | from . import debug 13 | 14 | handlermap = { 15 | "/api/init/init": init.init, 16 | "/api/gadgethost/getgadgets": gadgethost.getgadgets, 17 | "/api/menugadget/saveconfiguration": menugadget.saveconfiguration, 18 | "/api/statsgadget/getworkerstats": statsgadget.getworkerstats, 19 | "/api/statsgadget/getworksourcestats": statsgadget.getworksourcestats, 20 | "/api/statsgadget/getblockchainstats": statsgadget.getblockchainstats, 21 | "/api/statsgadget/getallstats": statsgadget.getallstats, 22 | "/api/log/stream": log.stream, 23 | "/api/uiconfig/read": uiconfig.read, 24 | "/api/uiconfig/write": uiconfig.write, 25 | "/api/frontendeditor/getfrontendclasses": frontendeditor.getfrontendclasses, 26 | "/api/frontendeditor/getfrontends": frontendeditor.getfrontends, 27 | "/api/frontendeditor/createfrontend": frontendeditor.createfrontend, 28 | "/api/frontendeditor/deletefrontend": frontendeditor.deletefrontend, 29 | "/api/frontendeditor/restartfrontend": frontendeditor.restartfrontend, 30 | "/api/workereditor/getworkerclasses": workereditor.getworkerclasses, 31 | "/api/workereditor/getworkers": workereditor.getworkers, 32 | "/api/workereditor/createworker": workereditor.createworker, 33 | "/api/workereditor/deleteworker": workereditor.deleteworker, 34 | "/api/workereditor/restartworker": workereditor.restartworker, 35 | "/api/worksourceeditor/getworksourceclasses": worksourceeditor.getworksourceclasses, 36 | "/api/worksourceeditor/getworksources": worksourceeditor.getworksources, 37 | "/api/worksourceeditor/createworksource": worksourceeditor.createworksource, 38 | "/api/worksourceeditor/deleteworksource": worksourceeditor.deleteworksource, 39 | "/api/worksourceeditor/restartworksource": worksourceeditor.restartworksource, 40 | "/api/worksourceeditor/moveworksource": worksourceeditor.moveworksource, 41 | "/api/worksourceeditor/getblockchains": worksourceeditor.getblockchains, 42 | "/api/worksourceeditor/setblockchain": worksourceeditor.setblockchain, 43 | "/api/blockchaineditor/getblockchains": blockchaineditor.getblockchains, 44 | "/api/blockchaineditor/createblockchain": blockchaineditor.createblockchain, 45 | "/api/blockchaineditor/deleteblockchain": blockchaineditor.deleteblockchain, 46 | "/api/settingseditor/readsettings": settingseditor.readsettings, 47 | "/api/settingseditor/writesettings": settingseditor.writesettings, 48 | "/api/debug/dumpthreadstates": debug.dumpthreadstates, 49 | } 50 | -------------------------------------------------------------------------------- /modules/theseven/webui/api/blockchaineditor.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | from ..decorators import jsonapi 24 | import traceback 25 | 26 | 27 | 28 | @jsonapi 29 | def getblockchains(core, webui, httprequest, path, request, privileges): 30 | return [{"id": b.id, "name": b.settings.name} for b in core.blockchains] 31 | 32 | 33 | 34 | @jsonapi 35 | def createblockchain(core, webui, httprequest, path, request, privileges): 36 | if privileges != "admin": return httprequest.send_response(403) 37 | try: 38 | name = request["name"] 39 | from core.blockchain import Blockchain 40 | blockchain = Blockchain(core) 41 | blockchain.settings.name = name 42 | blockchain.apply_settings() 43 | core.add_blockchain(blockchain) 44 | return {} 45 | except: return {"error": traceback.format_exc()} 46 | 47 | 48 | 49 | @jsonapi 50 | def deleteblockchain(core, webui, httprequest, path, request, privileges): 51 | if privileges != "admin": return httprequest.send_response(403) 52 | try: 53 | blockchain = core.registry.get(request["id"]) 54 | core.remove_blockchain(blockchain) 55 | blockchain.destroy() 56 | return {} 57 | except: return {"error": traceback.format_exc()} 58 | -------------------------------------------------------------------------------- /modules/theseven/webui/api/debug.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | import sys 24 | import threading 25 | import traceback 26 | from ..decorators import jsonapi 27 | 28 | 29 | 30 | @jsonapi 31 | def dumpthreadstates(core, webui, httprequest, path, request, privileges): 32 | id2name = dict([(th.ident, th.name) for th in threading.enumerate()]) 33 | code = [] 34 | for threadId, stack in sys._current_frames().items(): 35 | code.append("\n# Thread: %s(%d)" % (id2name.get(threadId,""), threadId)) 36 | for filename, lineno, name, line in traceback.extract_stack(stack): 37 | code.append('File: "%s", line %d, in %s' % (filename, lineno, name)) 38 | if line: code.append(" %s" % (line.strip())) 39 | return {"data": "\n".join(code)} 40 | -------------------------------------------------------------------------------- /modules/theseven/webui/api/frontendeditor.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | from ..decorators import jsonapi 24 | import traceback 25 | 26 | 27 | 28 | @jsonapi 29 | def getfrontendclasses(core, webui, httprequest, path, request, privileges): 30 | return [{"id": c.id, "version": c.version} for c in core.frontendclasses] 31 | 32 | 33 | 34 | @jsonapi 35 | def getfrontends(core, webui, httprequest, path, request, privileges): 36 | return [{"id": f.id, "name": f.settings.name, "class": f.__class__.id} for f in core.frontends] 37 | 38 | 39 | 40 | @jsonapi 41 | def createfrontend(core, webui, httprequest, path, request, privileges): 42 | if privileges != "admin": return httprequest.send_response(403) 43 | try: 44 | frontendclass = core.registry.get(request["class"]) 45 | frontend = frontendclass(core) 46 | core.add_frontend(frontend) 47 | return {} 48 | except: return {"error": traceback.format_exc()} 49 | 50 | 51 | 52 | @jsonapi 53 | def deletefrontend(core, webui, httprequest, path, request, privileges): 54 | if privileges != "admin": return httprequest.send_response(403) 55 | try: 56 | frontend = core.registry.get(request["id"]) 57 | core.remove_frontend(frontend) 58 | frontend.destroy() 59 | return {} 60 | except: return {"error": traceback.format_exc()} 61 | 62 | 63 | 64 | @jsonapi 65 | def restartfrontend(core, webui, httprequest, path, request, privileges): 66 | if privileges != "admin": return httprequest.send_response(403) 67 | try: 68 | frontend = core.registry.get(request["id"]) 69 | frontend.restart() 70 | return {} 71 | except: return {"error": traceback.format_exc()} 72 | -------------------------------------------------------------------------------- /modules/theseven/webui/api/gadgethost.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | from ..decorators import jsonapi 24 | 25 | 26 | 27 | @jsonapi 28 | def getgadgets(core, webui, httprequest, path, request, privileges): 29 | if request["collection"] == "dashboard": 30 | return [ 31 | {"width": 200, "entries": [ 32 | {"module": "menugadget", "moduleparam": None}, 33 | ]}, 34 | {"entries": [ 35 | {"module": "statsgadget", "moduleparam": None}, 36 | {"module": "loggadget", "moduleparam": None}, 37 | ]}, 38 | ] 39 | return [{"width": 0, "entries": []}] 40 | -------------------------------------------------------------------------------- /modules/theseven/webui/api/init.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | from ..decorators import jsonapi 24 | 25 | 26 | 27 | @jsonapi 28 | def init(core, webui, httprequest, path, request, privileges): 29 | return { 30 | "services": [[], ["nls", "errorlayer"]], 31 | "rootmodule": "theme", 32 | "rootmoduleparam": { "default": "default", "module": "gadgethost", "moduleparam": "dashboard" }, 33 | } 34 | -------------------------------------------------------------------------------- /modules/theseven/webui/api/log.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | from ..decorators import jsonapi 24 | import json 25 | try: from queue import Queue 26 | except: from Queue import Queue 27 | 28 | 29 | 30 | @jsonapi 31 | def stream(core, webui, httprequest, path, request, privileges): 32 | # Figure out the loglevel, by default send all messages 33 | loglevel = int(request["loglevel"]) if "loglevel" in request else 1000 34 | 35 | # Stream this by means of a chunked transfer 36 | httprequest.protocol_version = "HTTP/1.1" 37 | httprequest.log_request(200, "") 38 | httprequest.send_response(200) 39 | httprequest.send_header("Content-Type", "application/json") 40 | httprequest.send_header("Transfer-Encoding", "chunked") 41 | httprequest.end_headers() 42 | 43 | def write_chunk(data): 44 | data = data.encode("utf_8") 45 | httprequest.wfile.write(("%X\r\n" % len(data)).encode("ascii") + data + "\r\n".encode("ascii")) 46 | httprequest.wfile.flush() 47 | 48 | queue = Queue() 49 | 50 | try: 51 | # Register our log message queue 52 | webui.register_log_listener(queue) 53 | 54 | while True: 55 | # Wait for data to turn up in the queue 56 | message = queue.get() 57 | messages = [message] if message["loglevel"] <= loglevel else [] 58 | # If there's more in the queue, fetch that as well 59 | while True: 60 | try: message = queue.get_nowait() 61 | except: break 62 | if message["loglevel"] <= loglevel: messages.append(message) 63 | # Send the messages that we got to the client 64 | write_chunk(json.dumps(messages, ensure_ascii = False) + "\0") 65 | 66 | except: pass 67 | finally: webui.unregister_log_listener(queue) 68 | -------------------------------------------------------------------------------- /modules/theseven/webui/api/menugadget.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | from ..decorators import jsonapi 24 | import traceback 25 | 26 | 27 | 28 | @jsonapi 29 | def saveconfiguration(core, webui, httprequest, path, request, privileges): 30 | try: 31 | core.save() 32 | return {} 33 | except: return {"error": traceback.format_exc()} 34 | -------------------------------------------------------------------------------- /modules/theseven/webui/api/settingseditor.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | from ..decorators import jsonapi 24 | import traceback 25 | 26 | 27 | 28 | @jsonapi 29 | def readsettings(core, webui, httprequest, path, request, privileges): 30 | if privileges != "admin": return httprequest.send_response(403) 31 | try: 32 | item = core.registry.get(request["id"]) 33 | settings = {} 34 | for setting, data in item.__class__.settings.items(): 35 | settings[data["position"]] = {"name": setting, "spec": data, "value": item.settings[setting]} 36 | return {"settings": settings} 37 | except: return {"error": traceback.format_exc()} 38 | 39 | 40 | 41 | @jsonapi 42 | def writesettings(core, webui, httprequest, path, request, privileges): 43 | if privileges != "admin": return httprequest.send_response(403) 44 | try: 45 | item = core.registry.get(request["id"]) 46 | for setting in item.__class__.settings.keys(): 47 | if setting in request["settings"]: 48 | item.settings[setting] = request["settings"][setting] 49 | item.apply_settings() 50 | return {} 51 | except: return {"error": traceback.format_exc()} 52 | -------------------------------------------------------------------------------- /modules/theseven/webui/api/statsgadget.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | import time 24 | from ..decorators import jsonapi 25 | 26 | 27 | 28 | @jsonapi 29 | def getworkerstats(core, webui, httprequest, path, request, privileges): 30 | now = time.time() 31 | ghashes = core.stats.ghashes 32 | return { 33 | "timestamp": now, 34 | "starttime": core.stats.starttime, 35 | "ghashes": ghashes, 36 | "avgmhps": 1000. * ghashes / (now - core.stats.starttime), 37 | "workers": core.get_worker_statistics(), 38 | } 39 | 40 | 41 | @jsonapi 42 | def getworksourcestats(core, webui, httprequest, path, request, privileges): 43 | return { 44 | "timestamp": time.time(), 45 | "worksources": core.get_work_source_statistics(), 46 | } 47 | 48 | 49 | @jsonapi 50 | def getblockchainstats(core, webui, httprequest, path, request, privileges): 51 | return { 52 | "timestamp": time.time(), 53 | "blockchains": core.get_blockchain_statistics(), 54 | } 55 | 56 | 57 | @jsonapi 58 | def getallstats(core, webui, httprequest, path, request, privileges): 59 | now = time.time() 60 | ghashes = core.stats.ghashes 61 | return { 62 | "timestamp": now, 63 | "starttime": core.stats.starttime, 64 | "ghashes": ghashes, 65 | "avgmhps": 1000. * ghashes / (now - core.stats.starttime), 66 | "workers": core.get_worker_statistics(), 67 | "worksources": core.get_work_source_statistics(), 68 | "blockchains": core.get_blockchain_statistics(), 69 | } 70 | -------------------------------------------------------------------------------- /modules/theseven/webui/api/uiconfig.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | from ..decorators import jsonapi 24 | 25 | 26 | 27 | @jsonapi 28 | def read(core, webui, httprequest, path, request, privileges): 29 | return webui.settings.uiconfig 30 | 31 | 32 | 33 | @jsonapi 34 | def write(core, webui, httprequest, path, request, privileges): 35 | if privileges != "admin": return httprequest.send_response(403) 36 | webui.settings.uiconfig = request 37 | return {} 38 | -------------------------------------------------------------------------------- /modules/theseven/webui/api/workereditor.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | from ..decorators import jsonapi 24 | import traceback 25 | 26 | 27 | 28 | @jsonapi 29 | def getworkerclasses(core, webui, httprequest, path, request, privileges): 30 | return [{"id": c.id, "version": c.version} for c in core.workerclasses] 31 | 32 | 33 | 34 | @jsonapi 35 | def getworkers(core, webui, httprequest, path, request, privileges): 36 | return [{"id": w.id, "name": w.settings.name, "class": w.__class__.id} for w in core.workers] 37 | 38 | 39 | 40 | @jsonapi 41 | def createworker(core, webui, httprequest, path, request, privileges): 42 | if privileges != "admin": return httprequest.send_response(403) 43 | try: 44 | workerclass = core.registry.get(request["class"]) 45 | worker = workerclass(core) 46 | core.add_worker(worker) 47 | return {} 48 | except: return {"error": traceback.format_exc()} 49 | 50 | 51 | 52 | @jsonapi 53 | def deleteworker(core, webui, httprequest, path, request, privileges): 54 | if privileges != "admin": return httprequest.send_response(403) 55 | try: 56 | worker = core.registry.get(request["id"]) 57 | core.remove_worker(worker) 58 | worker.destroy() 59 | return {} 60 | except: return {"error": traceback.format_exc()} 61 | 62 | 63 | 64 | @jsonapi 65 | def restartworker(core, webui, httprequest, path, request, privileges): 66 | if privileges != "admin": return httprequest.send_response(403) 67 | try: 68 | worker = core.registry.get(request["id"]) 69 | worker.restart() 70 | return {} 71 | except: return {"error": traceback.format_exc()} 72 | -------------------------------------------------------------------------------- /modules/theseven/webui/api/worksourceeditor.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | from ..decorators import jsonapi 24 | import traceback 25 | 26 | 27 | 28 | @jsonapi 29 | def getworksourceclasses(core, webui, httprequest, path, request, privileges): 30 | return [{"id": c.id, "version": c.version, "is_group": c.is_group} for c in core.worksourceclasses] 31 | 32 | 33 | 34 | @jsonapi 35 | def getworksources(core, webui, httprequest, path, request, privileges): 36 | def format_work_source(worksource): 37 | data = {"id": worksource.id, "name": worksource.settings.name, 38 | "class": worksource.__class__.id, "is_group": worksource.is_group} 39 | if worksource.is_group: data["children"] = [format_work_source(c) for c in worksource.children] 40 | else: 41 | blockchain = worksource.get_blockchain() 42 | data["blockchain"] = blockchain.id if blockchain else 0 43 | return data 44 | return format_work_source(core.get_root_work_source()) 45 | 46 | 47 | 48 | @jsonapi 49 | def createworksource(core, webui, httprequest, path, request, privileges): 50 | if privileges != "admin": return httprequest.send_response(403) 51 | try: 52 | worksourceclass = core.registry.get(request["class"]) 53 | parent = core.registry.get(request["parent"]) 54 | worksource = worksourceclass(core) 55 | parent.add_work_source(worksource) 56 | return {} 57 | except: return {"error": traceback.format_exc()} 58 | 59 | 60 | 61 | @jsonapi 62 | def deleteworksource(core, webui, httprequest, path, request, privileges): 63 | if privileges != "admin": return httprequest.send_response(403) 64 | try: 65 | worksource = core.registry.get(request["id"]) 66 | if worksource.is_group: 67 | with worksource.childlock: 68 | for child in worksource.children: 69 | worksource.remove_work_source(child) 70 | child.destroy() 71 | worksource.get_parent().remove_work_source(worksource) 72 | worksource.destroy() 73 | return {} 74 | except: return {"error": traceback.format_exc()} 75 | 76 | 77 | 78 | @jsonapi 79 | def moveworksource(core, webui, httprequest, path, request, privileges): 80 | if privileges != "admin": return httprequest.send_response(403) 81 | try: 82 | worksource = core.registry.get(request["id"]) 83 | parent = core.registry.get(request["parent"]) 84 | parent.add_work_source(worksource) 85 | return {} 86 | except: return {"error": traceback.format_exc()} 87 | 88 | 89 | 90 | @jsonapi 91 | def getblockchains(core, webui, httprequest, path, request, privileges): 92 | return [{"id": b.id, "name": b.settings.name} for b in core.blockchains] 93 | 94 | 95 | 96 | @jsonapi 97 | def setblockchain(core, webui, httprequest, path, request, privileges): 98 | if privileges != "admin": return httprequest.send_response(403) 99 | try: 100 | worksource = core.registry.get(request["id"]) 101 | try: blockchain = core.registry.get(request["blockchain"]) 102 | except: blockchain = None 103 | worksource.set_blockchain(blockchain) 104 | return {} 105 | except: return {"error": traceback.format_exc()} 106 | 107 | 108 | 109 | @jsonapi 110 | def restartworksource(core, webui, httprequest, path, request, privileges): 111 | if privileges != "admin": return httprequest.send_response(403) 112 | try: 113 | worksource = core.registry.get(request["id"]) 114 | worksource.restart() 115 | return {} 116 | except: return {"error": traceback.format_exc()} 117 | -------------------------------------------------------------------------------- /modules/theseven/webui/decorators.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | import json 24 | import traceback 25 | 26 | 27 | 28 | class jsonapi(object): 29 | 30 | 31 | def __init__(self, f): 32 | self.f = f 33 | 34 | 35 | def __call__(self, core, webui, httprequest, path, privileges): 36 | try: 37 | # We only accept JSON. If this is something different => 400 Bad Request 38 | if httprequest.headers.get("content-type", None) not in ("application/json", "application/json; charset=UTF-8"): 39 | return httprequest.send_response(400) 40 | length = int(httprequest.headers.get("content-length")) 41 | # Read request from the connection 42 | data = b"" 43 | while len(data) < length: data += httprequest.rfile.read(length - len(data)) 44 | # Decode the request 45 | data = json.loads(data.decode("utf_8")) 46 | # Run the API function 47 | data = self.f(core, webui, httprequest, path, data, privileges) 48 | if data == None: return 49 | # Encode the response 50 | data = json.dumps(data, ensure_ascii = False, default = lambda obj: None).encode("utf_8") 51 | # Send response headers 52 | httprequest.log_request(200, len(data)) 53 | httprequest.send_response(200) 54 | httprequest.send_header("Content-Type", "application/json; charset=UTF-8") 55 | httprequest.send_header("Content-Length", len(data)) 56 | httprequest.end_headers() 57 | httprequest.wfile.write(data) 58 | # Something went wrong, no matter what => 500 Internal Server Error 59 | except: 60 | core.log(webui, "Exception while handling API call: %s\n" % traceback.format_exc(), 700, "y") 61 | try: httprequest.send_response(500) 62 | except: pass 63 | -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/contextmenu/contextmenu.js: -------------------------------------------------------------------------------- 1 | // Modular Python Bitcoin Miner WebUI 2 | // Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | // 18 | // Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | // want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | mod.contextmenu = { 22 | 23 | // Called on module initialisation, ensures that all dependencies are satisfied 24 | "init": function(callback) 25 | { 26 | depend(["event"], callback); 27 | }, 28 | 29 | "ContextMenu": function(style) 30 | { 31 | if (!style) style = ""; 32 | var obj = this; 33 | 34 | this.window = window; 35 | this.rootNode = document.createElement("div"); 36 | this.rootNode.className = "contextmenu contextmenu_" + style; 37 | this.rootNode.style.position = "absolute"; 38 | this.rootNode.style.zIndex = 50000; 39 | 40 | this.rootNode.onmouseout = function() 41 | { 42 | obj.timeout = setTimeout(obj.hide, 1000); 43 | }; 44 | 45 | this.rootNode.onmouseover = function() 46 | { 47 | if (obj.timeout) clearTimeout(obj.timeout); 48 | }; 49 | 50 | this.addEntry = function(name, callback, buttonstyle) 51 | { 52 | var text = document.createTextNode(name); 53 | var node = document.createElement("div"); 54 | node.className = "contextmenu_entry contextmenu_" + style + "_entry"; 55 | if (buttonstyle) node.className += " " + buttonstyle; 56 | node.appendChild(text); 57 | obj.rootNode.appendChild(node); 58 | if (!callback) callback = killEvent; 59 | node.onmousedown = callback; 60 | return node; 61 | }; 62 | 63 | this.addBarrier = function(barrierstyle) 64 | { 65 | var node = document.createElement("div"); 66 | node.className = "contextmenu_barrier contextmenu_" + style + "_barrier"; 67 | if (barrierstyle) node.className += " " + barrierstyle; 68 | obj.rootNode.appendChild(node); 69 | node.onmousedown = killEvent; 70 | return node; 71 | }; 72 | 73 | this.show = function(e) 74 | { 75 | if (!e) e = window.event; 76 | obj.rootNode.style.left = e.clientX + "px"; 77 | obj.rootNode.style.top = e.clientY + "px"; 78 | document.getElementById("container").appendChild(obj.rootNode); 79 | obj.mousehook = mod.event.hook("windowmousedown", obj.hide); 80 | obj.keyhook = mod.event.catchKey(27, obj.hide); 81 | return killEvent(e); 82 | }; 83 | 84 | this.hide = function(e) 85 | { 86 | if (obj.keyhook) obj.keyhook.unhook(); 87 | if (obj.mousehook) obj.mousehook.unhook(); 88 | if (obj.rootNode.parentNode) obj.rootNode.parentNode.removeChild(obj.rootNode); 89 | return killEvent(e); 90 | }; 91 | 92 | } 93 | 94 | }; -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/csc/csc.js: -------------------------------------------------------------------------------- 1 | // Modular Python Bitcoin Miner WebUI 2 | // Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | // 18 | // Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | // want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | mod.csc = { 22 | 23 | // Module initialisation: Check that all dependencies are satisfied 24 | "init": function(callback) 25 | { 26 | depend(["json"], callback); 27 | }, 28 | 29 | // Send a request to the server and call a callback as soon as the response arrives 30 | "request": function(module, filename, request, callback, params) 31 | { 32 | var buffer = ""; 33 | if (!params) params = new Array(); 34 | params.method = "POST"; 35 | params.uri = "api/" + module + "/" + filename; 36 | params.data = JSON.stringify(request); 37 | if (params.stream) 38 | params.streamcallback = function(data) 39 | { 40 | buffer += data; 41 | data = buffer.split("\0"); 42 | buffer = data[data.length - 1]; 43 | data[data.length - 1] = ""; 44 | for (var i in data) 45 | if (data.hasOwnProperty(i) && data[i].length > 0) 46 | try 47 | { 48 | callback(JSON.parse(data[i])); 49 | } 50 | catch (e) 51 | { 52 | log("Error while parsing stream message: " + e + "\nMessage: " + data[i]); 53 | } 54 | }; 55 | else 56 | params.callback = function(data) 57 | { 58 | callback(JSON.parse(data)); 59 | }; 60 | if (!params.header) params.header = new Array(); 61 | if (!params.header["Content-Type"]) params.header["Content-Type"] = "application/json"; 62 | return httprequest(params); 63 | } 64 | 65 | }; -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/debugmenu/debugmenu.js: -------------------------------------------------------------------------------- 1 | // Modular Python Bitcoin Miner WebUI 2 | // Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | // 18 | // Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | // want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | mod.debugmenu = { 22 | 23 | // Called on module initialisation, ensures that all dependencies are satisfied 24 | "init": function(callback) 25 | { 26 | depend(["csc", "dom", "layerbox", "uiconfig"], callback); 27 | }, 28 | 29 | // Shows the frontend editor window 30 | "LayerUI": function(config) 31 | { 32 | var box = mod.layerbox.LayerBox(); 33 | box.setTitle(nls("Debug menu")); 34 | box.setOuterWidth("200px"); 35 | 36 | var buttons = 37 | [ 38 | {"name": "Dump thread states", "module": "debugviewer", "moduleparam": {"function": "dumpthreadstates", "title": nls("Dump thread states")}}, 39 | ] 40 | 41 | for (var i in buttons) 42 | if (buttons.hasOwnProperty(i)) 43 | { 44 | var button = document.createElement("input"); 45 | button.type = "button"; 46 | button.style.width = "100%"; 47 | button.value = nls(buttons[i].name); 48 | button.data = buttons[i]; 49 | button.onclick = buttons[i].handler ? buttons[i].handler : function(e) 50 | { 51 | var obj = this; 52 | depend([obj.data.module], function() 53 | { 54 | mod[obj.data.module].LayerUI(obj.data.moduleparam); 55 | }); 56 | } 57 | box.contentNode.appendChild(button); 58 | } 59 | 60 | function saveconfiguration(e) 61 | { 62 | var obj = this; 63 | obj.disabled = true; 64 | obj.value = nls("Please wait..."); 65 | mod.csc.request("menugadget", "saveconfiguration", {}, function(data) 66 | { 67 | if (data.error) return error(data.error); 68 | obj.value = nls("Save configuration"); 69 | obj.disabled = false; 70 | }, {"cache": "none"}); 71 | } 72 | } 73 | 74 | }; 75 | -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/debugviewer/debugviewer.js: -------------------------------------------------------------------------------- 1 | // Modular Python Bitcoin Miner WebUI 2 | // Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | // 18 | // Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | // want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | mod.debugviewer = { 22 | 23 | // Called on module initialisation, ensures that all dependencies are satisfied 24 | "init": function(callback) 25 | { 26 | depend(["csc", "dom", "layerbox", "uiconfig"], callback); 27 | }, 28 | 29 | // Shows the frontend editor window 30 | "LayerUI": function(config) 31 | { 32 | var box = mod.layerbox.LayerBox(); 33 | box.setTitle(config.title); 34 | if (!mod.uiconfig.data.debugviewer) mod.uiconfig.data.debugviewer = {}; 35 | if (!mod.uiconfig.data.debugviewer.height) mod.uiconfig.data.debugviewer.height = "500px"; 36 | if (!mod.uiconfig.data.debugviewer.width) mod.uiconfig.data.debugviewer.width = "700px"; 37 | box.setOuterHeight(mod.uiconfig.data.debugviewer.height); 38 | box.setOuterWidth(mod.uiconfig.data.debugviewer.width); 39 | box.setResizable(true, true, function() 40 | { 41 | mod.uiconfig.data.debugviewer.height = box.rootNode.style.height; 42 | mod.uiconfig.data.debugviewer.width = box.rootNode.style.width; 43 | mod.uiconfig.update(); 44 | }); 45 | var div = document.createElement("div"); 46 | div.className = "pre autocursor"; 47 | div.style.height = "100%"; 48 | div.style.overflow = "auto"; 49 | div.allowSelect = true; 50 | div.allowDrag = true; 51 | div.allowContextMenu = true; 52 | box.contentNode.appendChild(div); 53 | var refreshButton = document.createElement("input"); 54 | refreshButton.type = "button"; 55 | refreshButton.value = nls("Refresh"); 56 | refreshButton.className = "box_titlebutton"; 57 | refreshButton.style.cssFloat = "right"; 58 | refreshButton.onclick = refresh; 59 | box.titleNode.appendChild(refreshButton); 60 | refresh(); 61 | function refresh() 62 | { 63 | showLoadingIndicator(div); 64 | mod.csc.request("debug", config["function"], {}, function(data) 65 | { 66 | mod.dom.clean(div); 67 | div.appendChild(document.createTextNode(data.data)); 68 | }, { "cache": "none" }); 69 | } 70 | } 71 | 72 | }; 73 | -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/dom/dom.js: -------------------------------------------------------------------------------- 1 | // Modular Python Bitcoin Miner WebUI 2 | // Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | // 18 | // Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | // want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | mod.dom = { 22 | 23 | // Remove all children of a specified DOM node 24 | "clean": function(node) 25 | { 26 | while (node.childNodes.length > 0) node.removeChild(node.childNodes[0]); 27 | }, 28 | 29 | // Make a node fill up the whole space of it's next reference parent node 30 | "fill": function(node) 31 | { 32 | node.className += " parentfiller"; 33 | }, 34 | 35 | "positionRelative": function(obj, relativeTo, left, top, invertx, inverty) 36 | { 37 | var node = relativeTo; 38 | while (node.offsetParent && node.offsetParent != document.documentElement) 39 | { 40 | top += node.offsetTop - node.scrollTop; 41 | left += node.offsetLeft - node.scrollLeft; 42 | node = node.offsetParent; 43 | } 44 | obj.style.position = "absolute"; 45 | if (invertx) obj.style.right = (document.documentElement.clientWidth - left) + "px"; 46 | else obj.style.left = left + "px"; 47 | if (inverty) obj.style.bottom = (document.documentElement.clientHeight - top) + "px"; 48 | else obj.style.top = top + "px"; 49 | if (obj.parentNode != node) node.appendChild(obj); 50 | }, 51 | 52 | "getAbsolutePos": function(obj) 53 | { 54 | var node = obj; 55 | var top = 0; 56 | var left = 0; 57 | while (node.offsetParent) 58 | { 59 | top += node.offsetTop - node.scrollTop; 60 | left += node.offsetLeft - node.scrollLeft; 61 | node = node.offsetParent; 62 | } 63 | return { "left": left, "top": top }; 64 | } 65 | 66 | }; -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/errorlayer/errorlayer.js: -------------------------------------------------------------------------------- 1 | // Modular Python Bitcoin Miner WebUI 2 | // Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | // 18 | // Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | // want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | mod.errorlayer = { 22 | 23 | // Module initialisation: Check that all dependencies are satisfied 24 | "init": function(callback) 25 | { 26 | depend(["event", "layerbox"], callback); 27 | }, 28 | 29 | "Service": function(callback) 30 | { 31 | // Replace the default error handler 32 | window.error = function(data, callback) 33 | { 34 | log(data); 35 | var box = new mod.layerbox.LayerBox(); 36 | box.rootNode.style.maxWidth = (document.getElementById("container").offsetWidth / 2) + "px"; 37 | if (/MSIE [4-6]/.test(navigator.userAgent)) 38 | box.rootNode.style.width = (document.getElementById("container").offsetWidth / 2) + "px"; 39 | box.setTitle(nls("An error occurred")); 40 | box.setStyle("error"); 41 | box.contentNode.appendChild(document.createTextNode(data)); 42 | box.contentNode.className += " pre textcursor"; 43 | box.contentNode.allowSelect = true; 44 | box.contentNode.allowDrag = true; 45 | box.contentNode.allowContextMenu = true; 46 | function dismiss() 47 | { 48 | box.destroy(); 49 | if (callback) callback(); 50 | } 51 | box.setCloseable(dismiss); 52 | box.events.push(mod.event.catchKey(13, dismiss)); 53 | box.events.push(mod.event.catchKey(27, dismiss)); 54 | }; 55 | callback(); 56 | } 57 | 58 | }; -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/event/event.js: -------------------------------------------------------------------------------- 1 | // Modular Python Bitcoin Miner WebUI 2 | // Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | // 18 | // Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | // want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | mod.event = { 22 | 23 | "hooks": {}, 24 | 25 | // Hook a callback to a specified event 26 | "hook": function(event, callback) 27 | { 28 | if (!mod.event.hooks[event]) mod.event.hooks[event] = new Array(); 29 | var hook = mod.event.hooks[event].push(callback) - 1; 30 | return { "unhook": function() { if (mod.event.hooks[event]) delete mod.event.hooks[event][hook]; } }; 31 | }, 32 | 33 | // Trigger all hooks connected to a specified event 34 | "trigger": function(event, param) 35 | { 36 | if (!mod.event.hooks[event]) return; 37 | var hooks = mod.event.hooks[event].slice().reverse(); 38 | for (var hook in hooks) 39 | if (hooks.hasOwnProperty(hook) && hooks[hook](param) == false) return false; 40 | }, 41 | 42 | "catchKey": function(keyCode, callback, allowBubble) 43 | { 44 | if (!allowBubble) allowBubble = false; 45 | return mod.event.hook("windowkeydown", function(e) 46 | { 47 | if (!e) e = window.event; 48 | if (e.keyCode == keyCode) 49 | { 50 | callback(e); 51 | return allowBubble; 52 | } 53 | }); 54 | } 55 | 56 | }; 57 | 58 | // Hook some system events 59 | window.onresize = function(e) 60 | { 61 | mod.event.trigger("windowresized", e); 62 | if (/MSIE [4-7]/.test(navigator.userAgent)) 63 | { 64 | setTimeout(function() 65 | { 66 | mod.event.trigger("windowresized", e); 67 | }, 1000); 68 | } 69 | }; 70 | window.onkeydown = function(e) 71 | { 72 | return mod.event.trigger("windowkeydown", e) == false ? killEvent(e) : true; 73 | }; 74 | window.onkeypress = function(e) 75 | { 76 | return mod.event.trigger("windowkeypress", e) == false ? killEvent(e) : true; 77 | }; 78 | window.onkeyup = function(e) 79 | { 80 | return mod.event.trigger("windowkeyup", e) == false ? killEvent(e) : true; 81 | }; 82 | window.onmousedown = function(e) 83 | { 84 | return mod.event.trigger("windowmousedown", e) == false ? killEvent(e) : true; 85 | }; 86 | window.onclick = function(e) 87 | { 88 | return mod.event.trigger("windowclick", e) == false ? killEvent(e) : true; 89 | }; 90 | window.onmouseup = function(e) 91 | { 92 | return mod.event.trigger("windowmouseup", e) == false ? killEvent(e) : true; 93 | }; -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/gadgethost/gadgethost.js: -------------------------------------------------------------------------------- 1 | // Modular Python Bitcoin Miner WebUI 2 | // Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | // 18 | // Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | // want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | mod.gadgethost = { 22 | 23 | // Called on module initialisation, ensures that all dependencies are satisfied 24 | "init": function(callback) 25 | { 26 | depend(["csc", "dom", "box"], callback); 27 | }, 28 | 29 | // Displays a collection of gadgets 30 | "InlineUI": function(range, config) 31 | { 32 | mod.dom.clean(range); 33 | 34 | var handles = []; 35 | mod.dom.clean(range); 36 | this.releaseRange = function() 37 | { 38 | for (var i in handles) 39 | if (handles.hasOwnProperty(i) && handles[i].releaseRange) 40 | handles[i].releaseRange(); 41 | }; 42 | 43 | function loadgadget(box, module, moduleparam) 44 | { 45 | depend([module], function() 46 | { 47 | handles.push(new mod[module].Gadget(box, moduleparam)); 48 | }); 49 | } 50 | 51 | mod.csc.request("gadgethost", "getgadgets", { "collection": config }, function(data) 52 | { 53 | mod.dom.clean(range); 54 | var table = document.createElement("table"); 55 | table.style.width = "100%"; 56 | var tbody = document.createElement("tbody"); 57 | var tr = document.createElement("tr"); 58 | for (var i in data) 59 | if (data.hasOwnProperty(i)) 60 | { 61 | var td = document.createElement("td"); 62 | if (data[i].width) td.style.width = data[i].width + "px"; 63 | var table2 = document.createElement("table"); 64 | table2.style.width = "100%"; 65 | var tbody2 = document.createElement("tbody"); 66 | for (var j in data[i].entries) 67 | if (data[i].entries.hasOwnProperty(j)) 68 | { 69 | var tr2 = document.createElement("tr"); 70 | var td2 = document.createElement("td"); 71 | if (data[i].entries[j].height) td2.style.height = data[i].entries[j].height + "px"; 72 | td2.style.padding = "1px"; 73 | var box = new mod.box.Box(); 74 | box.setOuterWidth("100%"); 75 | box.setOuterHeight("100%"); 76 | loadgadget(box, data[i].entries[j].module, data[i].entries[j].moduleparam); 77 | td2.appendChild(box.rootNode); 78 | tr2.appendChild(td2); 79 | tbody2.appendChild(tr2); 80 | } 81 | table2.appendChild(tbody2); 82 | td.appendChild(table2); 83 | tr.appendChild(td); 84 | } 85 | tbody.appendChild(tr); 86 | table.appendChild(tbody); 87 | range.appendChild(table); 88 | }); 89 | } 90 | 91 | }; 92 | -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/init/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSeven/Modular-Python-Bitcoin-Miner/4d3ac96712678191a065a01745fb1ae00610b7df/modules/theseven/webui/wwwroot/static/init/loading.gif -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/json/json.js: -------------------------------------------------------------------------------- 1 | // Modular Python Bitcoin Miner WebUI 2 | // Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | // 18 | // Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | // want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | mod.json = { 22 | 23 | "init": function(callback) 24 | { 25 | // Augment the Array prototype to include a function to convert the array into a JSON string 26 | Array.prototype.toJSONString = function() 27 | { 28 | var out = "["; 29 | var comma; 30 | 31 | // Append a string fragment to the output, preceded by a comma if neccessary 32 | function append(string) 33 | { 34 | if (comma) out += ","; 35 | out += string; 36 | comma = true; 37 | } 38 | 39 | for (var i = 0; i < this.length; i++) 40 | if (this[i] && typeof this[i].toJSONString === "function") append(this[i].toJSONString()); 41 | else append("null"); 42 | 43 | return out + "]"; 44 | }; 45 | 46 | // Augment the Boolean prototype to include a function to convert the boolean into a JSON string 47 | Boolean.prototype.toJSONString = function() 48 | { 49 | return String(this); 50 | }; 51 | 52 | // Augment the Date prototype to include a function to convert the date into a JSON string 53 | Date.prototype.toJSONString = function() 54 | { 55 | // Prepend a zero to one-digit numbers 56 | function pad(number) 57 | { 58 | return number < 10 ? "0" + n : n; 59 | } 60 | 61 | return "\"" + this.getFullYear() + "-" + pad(this.getMonth() + 1) + "-" + pad(this.getDate()) + "T" 62 | + pad(this.getHours()) + ":" + pad(this.getMinutes()) + ":" + pad(this.getSeconds()) + "\""; 63 | }; 64 | 65 | // Augment the Number prototype to include a function to convert the number into a JSON string 66 | Number.prototype.toJSONString = function() 67 | { 68 | return isFinite(this) ? String(this) : "null"; 69 | }; 70 | 71 | // Augment the Object prototype to include a function to convert the object into a JSON string 72 | Object.prototype.toJSONString = function() 73 | { 74 | var out = "{"; 75 | var comma; 76 | var key; 77 | 78 | // Append a string fragment to the output, preceded by the key and a comma if neccessary 79 | function append(string) 80 | { 81 | if (comma) out += ","; 82 | out += key.toJSONString() + ":" + string; 83 | comma = true; 84 | } 85 | 86 | for (key in this) 87 | if (this.hasOwnProperty(key)) 88 | { 89 | if (this[key] && typeof this[key].toJSONString === "function") append(this[key].toJSONString()); 90 | else append("null"); 91 | } 92 | 93 | return out + "}"; 94 | }; 95 | 96 | 97 | // Augment the String prototype to include a function to convert the string into a JSON string 98 | String.prototype.toJSONString = function() 99 | { 100 | // Conversion table for control characters 101 | var conv = { "\b": "\\b", "\t": "\\t", "\n": "\\n", "\f": "\\f", "\r": "\\r", "\"": "\\\"", "\\": "\\\\" }; 102 | 103 | if (/["\\\x00-\x1f]/.test(this)) 104 | { 105 | return "\"" + this.replace(/([\x00-\x1f\\"])/g, function(dummy, b) 106 | { 107 | if (conv[b]) return conv[b]; 108 | return "\\u00" + Math.floor(b.charCodeAt() / 16).toString(16) + (b.charCodeAt() % 16).toString(16); 109 | }) + "\""; 110 | } 111 | 112 | return "\"" + this + "\""; 113 | }; 114 | 115 | // Augment the String prototype to include a function to decode a JSON string 116 | String.prototype.decodeJSON = function() 117 | { 118 | try 119 | { 120 | return eval("(" + this + ")"); 121 | } 122 | catch (e) 123 | { 124 | throw ("json: Got some junk. Error: " + e.toString() + "\n\nData:\n" + this); 125 | } 126 | }; 127 | 128 | // Emulate native JSON for pre-ECMAScript 3.1 browsers 129 | if (!window.JSON) 130 | window.JSON = { 131 | "parse": function(data) 132 | { 133 | return data.decodeJSON(); 134 | }, 135 | "stringify": function(data) 136 | { 137 | return data.toJSONString(); 138 | } 139 | }; 140 | 141 | // Report successful initialisation of the module 142 | callback(); 143 | } 144 | 145 | }; -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/layer/layer.js: -------------------------------------------------------------------------------- 1 | // Modular Python Bitcoin Miner WebUI 2 | // Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | // 18 | // Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | // want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | mod.layer = { 22 | 23 | "zindex": 10000, 24 | 25 | // Make something be a layer 26 | "layerify": function(anchor, handle, win) 27 | { 28 | if (!win) win = window; 29 | var sizemaster = document.getElementById("container"); 30 | if (window != win) sizemaster = win; 31 | 32 | anchor.style.zIndex = mod.layer.zindex++; 33 | 34 | // Moves the layer to the specified position, clipped to fit into the viewport 35 | anchor.moveTo = function(x, y) 36 | { 37 | if (x > sizemaster.offsetWidth - anchor.offsetWidth) x = sizemaster.offsetWidth - anchor.offsetWidth; 38 | if (y > sizemaster.offsetHeight - anchor.offsetHeight) y = sizemaster.offsetHeight - anchor.offsetHeight; 39 | if (x < 0) x = 0; 40 | if (y < 0) y = 0; 41 | anchor.style.left = x + "px"; 42 | anchor.style.top = y + "px"; 43 | }; 44 | 45 | // Moves the layer by a specified offset 46 | anchor.moveBy = function(x, y) 47 | { 48 | anchor.moveTo(anchor.offsetLeft + x, anchor.offsetTop + y); 49 | }; 50 | 51 | anchor.onmousedown = function(e) 52 | { 53 | anchor.style.zIndex = mod.layer.zindex++; 54 | }; 55 | 56 | // We need to hook these events natively, 57 | // firing up event_trigger for every mouse move would kill most browsers 58 | handle.onmousedown = function(e) 59 | { 60 | anchor.style.zIndex = mod.layer.zindex++; 61 | 62 | // Backup the old event handlers 63 | var oldMouseUp = win.document.documentElement.onmouseup; 64 | var oldMouseMove = win.document.documentElement.onmousemove; 65 | function getMousePos(e) 66 | { 67 | if (!e) e = win.event; 68 | return { "x": e.clientX, "y": e.clientY }; 69 | } 70 | var pos = getMousePos(e); 71 | function updatePos(e) 72 | { 73 | // Determine target position, trim it to the window or content dimensions and apply it 74 | var newpos = getMousePos(e); 75 | anchor.moveBy(newpos.x - pos.x, newpos.y - pos.y); 76 | pos = newpos; 77 | } 78 | win.document.documentElement.onmousemove = updatePos; 79 | win.document.documentElement.onmouseup = function(e) 80 | { 81 | // Update the position a final time 82 | updatePos(e); 83 | // Restore the old event handlers 84 | win.document.documentElement.onmousemove = oldMouseMove; 85 | win.document.documentElement.onmouseup = oldMouseUp; 86 | }; 87 | return killEvent(e); 88 | }; 89 | } 90 | 91 | }; -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/layerbox/layerbox.js: -------------------------------------------------------------------------------- 1 | // Modular Python Bitcoin Miner WebUI 2 | // Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | // 18 | // Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | // want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | mod.layerbox = { 22 | 23 | "params": {"xmin": 10, "xmax": 50, "xstep": 10, 24 | "ymin": 10, "ymax": 60, "ystep": 10}, 25 | 26 | // Module initialization: Check that all dependencies are satisfied 27 | "init": function(callback) 28 | { 29 | depend(["box", "layer"], callback); 30 | }, 31 | 32 | // Allow themes to configure the opening position of layer boxes 33 | "setParams": function(params) 34 | { 35 | mod.layerbox.params = params; 36 | }, 37 | 38 | // The JS class representing a layer box 39 | "LayerBox": function(anchor, win) 40 | { 41 | if (!win) win = window; 42 | var box = new mod.box.Box(win); 43 | // Upper case Box here to not confuse it with a box style name 44 | box.rootNode.className += " LayerBox"; 45 | box.rootNode.style.position = "absolute"; 46 | mod.layer.layerify(box.rootNode, box.titleNode, win); 47 | if (!anchor) anchor = document.getElementsByTagName("body")[0]; 48 | box.setCloseable(box.destroy); 49 | anchor.appendChild(box.rootNode); 50 | box.moveTo = box.rootNode.moveTo; 51 | box.moveBy = box.rootNode.moveBy; 52 | if (!mod.layerbox.params.xcurrent || mod.layerbox.params.xcurrent > mod.layerbox.params.xmax) 53 | mod.layerbox.params.xcurrent = mod.layerbox.params.xmin; 54 | if (!mod.layerbox.params.ycurrent || mod.layerbox.params.ycurrent > mod.layerbox.params.ymax) 55 | mod.layerbox.params.ycurrent = mod.layerbox.params.ymin; 56 | box.moveTo(mod.layerbox.params.xcurrent, mod.layerbox.params.ycurrent); 57 | mod.layerbox.params.xcurrent += mod.layerbox.params.xstep; 58 | mod.layerbox.params.ycurrent += mod.layerbox.params.ystep; 59 | return box; 60 | } 61 | 62 | }; -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/menugadget/menugadget.js: -------------------------------------------------------------------------------- 1 | // Modular Python Bitcoin Miner WebUI 2 | // Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | // 18 | // Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | // want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | mod.menugadget = { 22 | 23 | // Called on module initialisation, ensures that all dependencies are satisfied 24 | "init": function(callback) 25 | { 26 | depend(["dom", "box", "event"], callback); 27 | }, 28 | 29 | // Shows a list of buttons that launch layers 30 | "Gadget": function(box, config) 31 | { 32 | mod.dom.clean(box.contentNode); 33 | box.setTitle(nls("Menu")); 34 | 35 | var buttons = 36 | [ 37 | {"name": "Frontends", "module": "frontendeditor", "moduleparam": null}, 38 | {"name": "Workers", "module": "workereditor", "moduleparam": null}, 39 | {"name": "Work sources", "module": "worksourceeditor", "moduleparam": null}, 40 | {"name": "Blockchains", "module": "blockchaineditor", "moduleparam": null}, 41 | {"name": "Save configuration", "handler": saveconfiguration}, 42 | {"name": "Debug menu", "module": "debugmenu", "moduleparam": null}, 43 | ] 44 | 45 | for (var i in buttons) 46 | if (buttons.hasOwnProperty(i)) 47 | { 48 | var button = document.createElement("input"); 49 | button.type = "button"; 50 | button.style.width = "100%"; 51 | button.value = nls(buttons[i].name); 52 | button.data = buttons[i]; 53 | button.onclick = buttons[i].handler ? buttons[i].handler : function(e) 54 | { 55 | var obj = this; 56 | depend([obj.data.module], function() 57 | { 58 | mod[obj.data.module].LayerUI(obj.data.moduleparam); 59 | }); 60 | } 61 | box.contentNode.appendChild(button); 62 | } 63 | 64 | function saveconfiguration(e) 65 | { 66 | var obj = this; 67 | obj.disabled = true; 68 | obj.value = nls("Please wait..."); 69 | mod.csc.request("menugadget", "saveconfiguration", {}, function(data) 70 | { 71 | if (data.error) return error(data.error); 72 | obj.value = nls("Save configuration"); 73 | obj.disabled = false; 74 | }, {"cache": "none"}); 75 | } 76 | } 77 | 78 | }; 79 | -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/nls/nls.js: -------------------------------------------------------------------------------- 1 | // Modular Python Bitcoin Miner WebUI 2 | // Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | // 18 | // Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | // want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | mod.nls = { 22 | 23 | // Module initialisation: Check that all dependencies are satisfied 24 | "init": function(callback) 25 | { 26 | window.nls = mod.nls.translate; 27 | depend(["event"], callback); 28 | }, 29 | 30 | // Load the default language pack 31 | "Service": function(callback) 32 | { 33 | mod.nls.loadlang(lang, callback); 34 | }, 35 | 36 | // Translate a message, if possible 37 | "translate": function(message, category) 38 | { 39 | if (!category) category = "general"; 40 | if (mod.nls.data) 41 | { 42 | if ((typeof mod.nls.data[category]) == "undefined") 43 | log("nls: Category not found in lang " + lang + ": "+category); 44 | else if (!mod.nls.data[category]); 45 | else if ((typeof mod.nls.data[category][message]) == "undefined") 46 | log("nls: Message not found in lang " + lang + ", category "+category+": "+message); 47 | else if ((typeof mod.nls.data[category][message]) == "string") 48 | return mod.nls.data[category][message]; 49 | } 50 | return message; 51 | }, 52 | 53 | // Load a language pack 54 | "loadlang": function(lang,callback) 55 | { 56 | httprequest({"method": "GET", "uri": "static/nls/lang/" + lang + ".json", "callback": function(data) 57 | { 58 | mod.nls.data = eval("(" + data.substr(data.indexOf("{")) + ")"); 59 | mod.event.trigger("nls_changed"); 60 | if (callback) callback(); 61 | }, "error": function(data) 62 | { 63 | log("nls: Unsupported lang " + lang + "!"); 64 | if (callback) callback(); 65 | } 66 | }); 67 | } 68 | 69 | }; -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/storage/storage.js: -------------------------------------------------------------------------------- 1 | // Modular Python Bitcoin Miner WebUI 2 | // Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | // 18 | // Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | // want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | mod.storage = { 22 | 23 | "write": function(name, value, session, time, allowCookie) 24 | { 25 | var store; 26 | if (session) store = sessionStorage; 27 | else if (window.localStorage) store = localStorage; 28 | else if (window.globalStorage) store = globalStorage[location.hostname]; 29 | if (store) 30 | { 31 | try 32 | { 33 | store.setItem(name, value); 34 | if (time) store.setItem("storage_expires_" + name, new Date(new Date().getTime() + time).getTime()); 35 | return true; 36 | } 37 | catch (e) 38 | { 39 | error(nls("Locally storing some data failed, probably because of an exceeded quota.\n" 40 | + "Please allow more storage space for this site in your browser settings.\nDetails:\n") + e); 41 | return false; 42 | } 43 | } 44 | else 45 | { 46 | if (allowCookie) 47 | { 48 | var expires = ""; 49 | if (!session) expires = "Tue, 19 Jan 2038 03:14:07 GMT"; 50 | if (time) expires = "; expires=" + new Date(new Date().getTime() + time).toGMTString(); 51 | document.cookie = escape(name) + "=" + escape(value) + expires; 52 | if (mod.storage.read(name) != value) 53 | { 54 | error(nls("Locally storing some data failed, because no supported storage mechanism worked.\n" 55 | + "Please update to a more recent browser and/or enable DOM storage in your browser settings to resolve this issue.")); 56 | return false; 57 | } 58 | } 59 | /* 60 | notify(nls("Warning: Incompatible browser"), 61 | nls("You may experience some issues, because your browser does not seem to support current client-side storage mechanisms.\n" 62 | + "Please update to a more recent browser and/or enable DOM storage in your browser settings to resolve this issue.")); 63 | */ 64 | return allowCookie; 65 | } 66 | }, 67 | 68 | "read": function(name) 69 | { 70 | if (window.sessionStorage && sessionStorage.getItem(name) && (!sessionStorage.getItem("storage_expires_" + name) 71 | || sessionStorage.getItem("storage_expires_" + name) > new Date().getTime())) 72 | return sessionStorage.getItem(name); 73 | if (window.localStorage && localStorage[name] && (!localStorage.getItem("storage_expires_" + name) 74 | || localStorage.getItem("storage_expires_" + name) > new Date().getTime())) 75 | return localStorage.getItem(name); 76 | if (window.globalStorage && globalStorage[location.hostname] && globalStorage[location.hostname].getItem(name) 77 | && (!globalStorage[location.hostname].getItem("storage_expires_" + name) 78 | || globalStorage[location.hostname].getItem("storage_expires_" + name) > new Date().getTime())) 79 | return globalStorage[location.hostname].getItem(name); 80 | var name = escape(name) + "="; 81 | var cookies = document.cookie.split(";"); 82 | for (var i = 0; i < cookies.length; i++) 83 | { 84 | while (cookies[i].charAt(0) == " ") cookies[i] = cookies[i].substr(1, cookies[i].length - 1); 85 | if (cookies[i].indexOf(name) == 0) 86 | return unescape(cookies[i].substring(name.length, cookies[i].length)); 87 | } 88 | }, 89 | 90 | "erase": function(name) 91 | { 92 | if (window.sessionStorage) sessionStorage.removeItem(name); 93 | if (window.localStorage) localStorage.removeItem(name); 94 | if (window.globalStorage && globalStorage[location.hostname]) globalStorage[location.hostname].removeItem(name); 95 | document.cookie = escape(name) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT"; 96 | } 97 | 98 | }; 99 | -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/theme/data/default/default.css: -------------------------------------------------------------------------------- 1 | /* 2 | Modular Python Bitcoin Miner WebUI 3 | Copyright (C) 2012 Michael Sparmann (TheSeven) 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | 19 | Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 20 | want to support further development of the Modular Python Bitcoin Miner. 21 | */ 22 | 23 | /* XHR loading indicator */ 24 | #loading 25 | { 26 | bottom: 0px; 27 | } 28 | 29 | /* Global font */ 30 | body, table 31 | { 32 | font: 12px Arial,Helvetica,sans-serif; 33 | } 34 | 35 | /* Get rid of all those text-select cursors */ 36 | * 37 | { 38 | cursor: default; 39 | } 40 | input[type=text], input[type=password], textarea, .autocursor, .autocursor * 41 | { 42 | cursor: auto; 43 | } 44 | .textcursor, .textcursor * 45 | { 46 | cursor: text; 47 | } 48 | 49 | /* Link markup */ 50 | .link 51 | { 52 | text-decoration: underline; 53 | font-weight: bold; 54 | color: #00d; 55 | cursor: pointer; 56 | } 57 | 58 | /* Label markup */ 59 | .box_form_label 60 | { 61 | font-weight: bold; 62 | text-align: right; 63 | vertical-align: middle; 64 | padding-right: 5px; 65 | } 66 | 67 | /* Button in the title bar of a box */ 68 | input.box_titlebutton 69 | { 70 | padding: 0px 2px; 71 | margin: -2px 0px; 72 | } 73 | 74 | /* Minimum widths */ 75 | .windowfiller 76 | { 77 | min-width: 750px; 78 | } 79 | 80 | /* Visible tables */ 81 | table.table_visible, .table_visible table, .table_visible th, .table_visible td 82 | { 83 | border: 1px solid #007; 84 | vertical-align: middle; 85 | text-align: center; 86 | } 87 | 88 | .table_visible th, .table_visible td 89 | { 90 | padding: 3px; 91 | } 92 | 93 | /* Invisible tables */ 94 | table.table_invisible, .table_invisible table, .table_invisible th, .table_invisible td 95 | { 96 | border: 0px; 97 | padding: 0px; 98 | } 99 | 100 | /* Table default alignment classes */ 101 | table.table_left, .table_left table, .table_left th, .table_left td 102 | { 103 | text-align: left; 104 | } 105 | 106 | table.table_center, .table_center table, .table_center th, .table_center td 107 | { 108 | text-align: center; 109 | } 110 | 111 | table.table_right, .table_right table, .table_right th, .table_right td 112 | { 113 | text-align: right; 114 | } 115 | 116 | table.table_top, .table_top table, .table_top th, .table_top td 117 | { 118 | vertical-align: top; 119 | } 120 | 121 | table.table_middle, .table_middle table, .table_middle th, .table_middle td 122 | { 123 | vertical-align: middle; 124 | } 125 | 126 | table.table_bottom, .table_bottom table, .table_bottom th, .table_bottom td 127 | { 128 | vertical-align: bottom; 129 | } 130 | 131 | /* Box style */ 132 | .box 133 | { 134 | border-style: solid; 135 | border-color: rgb(153, 229, 255) rgb(51, 76, 102) rgb(51, 76, 102) rgb(153, 229, 255); 136 | border-width: 1px; 137 | background-color: rgb(102, 153, 204); 138 | text-align: left; 139 | } 140 | 141 | .box_topleft 142 | { 143 | height: 16px; 144 | width: 1px; 145 | } 146 | 147 | .box_title 148 | { 149 | height: 16px; 150 | vertical-align: middle; 151 | color: #fff; 152 | font-family: Arial,SunSans-Regular; 153 | font-size: 12px; 154 | text-decoration: none; 155 | font-weight: bold; 156 | padding: 1px; 157 | } 158 | 159 | .box_topright 160 | { 161 | height: 16px; 162 | width: 1px; 163 | } 164 | 165 | .box_left 166 | { 167 | width: 1px; 168 | } 169 | 170 | .box_content 171 | { 172 | border-style: solid; 173 | border-color: rgb(51, 76, 102) rgb(153, 229, 255) rgb(153, 229, 255) rgb(51, 76, 102); 174 | border-width: 1px; 175 | background-color: #fff; 176 | table-layout: fixed; 177 | padding: 2px; 178 | } 179 | 180 | .box_right 181 | { 182 | width: 1px; 183 | } 184 | 185 | .box_bottomleft 186 | { 187 | height: 1px; 188 | width: 1px; 189 | } 190 | 191 | .box_bottom 192 | { 193 | height: 2px; 194 | } 195 | 196 | .box_bottomright 197 | { 198 | height: 1px; 199 | width: 1px; 200 | } 201 | 202 | .box_close 203 | { 204 | margin: 1px; 205 | background: url("images/closebutton.gif") no-repeat; 206 | height: 12px; 207 | width: 13px; 208 | float: right; 209 | } 210 | 211 | .errorbox 212 | { 213 | border-style: solid; 214 | border-width: 1px; 215 | text-align: left; 216 | border-color: rgb(255, 0, 0) rgb(95, 0, 0) rgb(95, 0, 0) rgb(255, 0, 0); 217 | background-color: rgb(191, 0, 0); 218 | } 219 | 220 | .errorbox .box_content 221 | { 222 | border-color: rgb(95, 0, 0) rgb(255, 0, 0) rgb(255, 0, 0) rgb(95, 0, 0); 223 | } 224 | 225 | /* Disconnect error message style */ 226 | .error_disconnect 227 | { 228 | text-align: center; 229 | font-weight: bold; 230 | font-size: 24px; 231 | position: relative; 232 | top: 300px; 233 | } 234 | 235 | /* Context menu */ 236 | 237 | .contextmenu 238 | { 239 | background-color: #cce; 240 | border: 1px outset #cce; 241 | } 242 | 243 | .contextmenu_entry 244 | { 245 | padding: 3px; 246 | } 247 | 248 | .contextmenu_entry:hover 249 | { 250 | background-color: #aaf; 251 | } 252 | 253 | .contextmenu_disabled 254 | { 255 | color: #33f; 256 | } 257 | 258 | .contextmenu_disabled:hover 259 | { 260 | background-color: #cce; 261 | } 262 | 263 | .contextmenu_barrier 264 | { 265 | margin: 5px; 266 | border: 1px inset #cce; 267 | } 268 | -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/theme/data/default/default.js: -------------------------------------------------------------------------------- 1 | // Modular Python Bitcoin Miner WebUI 2 | // Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | // 18 | // Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | // want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | mod.theme.data["default"] = { 22 | 23 | // Called on module initialisation, ensures that all dependencies are satisfied 24 | "init": function(callback) 25 | { 26 | depend(["dom", "layerbox"], callback); 27 | }, 28 | 29 | // Load the stylesheet and set up a bunch of divs to contain other components 30 | "InlineUI": function(range, config) 31 | { 32 | if ((typeof config) == "string") config = JSON.parse(config); 33 | var oldcount = document.styleSheets.length; 34 | var style = document.createElement("link"); 35 | var hook; 36 | var content; 37 | var alive = true; 38 | mod.dom.clean(range); 39 | mod.layerbox.setParams({"xmin": 250, "xmax": 350, "xstep": 20, 40 | "ymin": 100, "ymax": 180, "ystep": 20}); 41 | style.rel = "stylesheet"; 42 | style.type = "text/css"; 43 | style.href = "static/theme/data/default/default.css"; 44 | document.getElementsByTagName("head")[0].appendChild(style); 45 | function wait() 46 | { 47 | if (!alive) return; 48 | if (document.styleSheets.length < oldcount + 1) setTimeout(wait, 10); 49 | else 50 | { 51 | content = document.createElement("div"); 52 | content.style.position = "absolute"; 53 | content.style.left = "0px"; 54 | content.style.right = "0px"; 55 | content.style.top = "0px"; 56 | content.style.bottom = "0px"; 57 | content.style.overflow = "auto"; 58 | range.appendChild(content); 59 | var module = config.module; 60 | var moduleparam = config.moduleparam; 61 | if (params.module) 62 | { 63 | module = params.module; 64 | moduleparam = params.moduleparam; 65 | } 66 | delegate(content, module, moduleparam); 67 | callback(); 68 | } 69 | } 70 | wait(); 71 | 72 | this.releaseRange = function() 73 | { 74 | alive = false; 75 | if (hook) hook.unhook(); 76 | if (content && content.owner && content.owner.releaseRange) content.owner.releaseRange(); 77 | style.parentNode.removeChild(style); 78 | } 79 | } 80 | 81 | }; -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/theme/data/default/images/closebutton.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheSeven/Modular-Python-Bitcoin-Miner/4d3ac96712678191a065a01745fb1ae00610b7df/modules/theseven/webui/wwwroot/static/theme/data/default/images/closebutton.gif -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/theme/theme.js: -------------------------------------------------------------------------------- 1 | // Modular Python Bitcoin Miner WebUI 2 | // Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | // 18 | // Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | // want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | mod.theme = { 22 | 23 | "data": {}, 24 | 25 | // Module initialisation: Check that all dependencies are satisfied 26 | "init": function(callback) 27 | { 28 | depend(["json", "event"], callback); 29 | }, 30 | 31 | // The user interface class, which will delegate it's range to the actual theme handler 32 | "InlineUI": function(range, config) 33 | { 34 | if ((typeof config) == "string") config = JSON.parse(config); 35 | var theme; 36 | if (config.theme) theme = config.theme; 37 | else if (params.theme) theme = params.theme; 38 | else if (config["default"]) theme = config["default"]; 39 | else return error("theme: Could not determine theme for config " + JSON.stringify(config)); 40 | if (theme) delegate(range, "theme/data/" + theme, config); 41 | } 42 | 43 | }; -------------------------------------------------------------------------------- /modules/theseven/webui/wwwroot/static/uiconfig/uiconfig.js: -------------------------------------------------------------------------------- 1 | // Modular Python Bitcoin Miner WebUI 2 | // Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | // 18 | // Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | // want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | mod.uiconfig = { 22 | 23 | "data": {}, 24 | 25 | "timeout": false, 26 | 27 | // Module initialisation: Check that all dependencies are satisfied 28 | "init": function(callback) 29 | { 30 | depend(["csc"], function() 31 | { 32 | mod.csc.request("uiconfig", "read", {}, function(data) 33 | { 34 | mod.uiconfig.data = data; 35 | callback(); 36 | }); 37 | }); 38 | }, 39 | 40 | // Accumulate config update requests for up to 10 seconds, and then send the config to the server 41 | "update": function() 42 | { 43 | if (mod.uiconfig.timeout) return; 44 | mod.uiconfig.timeout = setTimeout(function() 45 | { 46 | mod.uiconfig.timeout = false; 47 | mod.csc.request("uiconfig", "write", mod.uiconfig.data); 48 | }, 10000); 49 | } 50 | 51 | }; -------------------------------------------------------------------------------- /modules/theseven/ztex/__init__.py: -------------------------------------------------------------------------------- 1 | from .ztexworker import ZtexWorker 2 | from .ztexhotplug import ZtexHotplugWorker 3 | 4 | workerclasses = [ZtexWorker, ZtexHotplugWorker] 5 | -------------------------------------------------------------------------------- /modules/theseven/ztex/boardproxy.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ############################################################### 24 | # ZTEX USB FPGA Module out of process board access dispatcher # 25 | ############################################################### 26 | 27 | 28 | 29 | import time 30 | import signal 31 | import struct 32 | import traceback 33 | from threading import Thread, Condition, RLock 34 | from multiprocessing import Process 35 | from core.job import Job 36 | from .driver import ZtexDevice 37 | 38 | 39 | class ZtexBoardProxy(Process): 40 | 41 | 42 | def __init__(self, rxconn, txconn, serial, takeover, firmware, pollinterval): 43 | super(ZtexBoardProxy, self).__init__() 44 | self.rxconn = rxconn 45 | self.txconn = txconn 46 | self.serial = serial 47 | self.takeover = takeover 48 | self.firmware = firmware 49 | self.pollinterval = pollinterval 50 | 51 | 52 | def run(self): 53 | signal.signal(signal.SIGINT, signal.SIG_IGN) 54 | signal.signal(signal.SIGTERM, signal.SIG_IGN) 55 | self.lock = RLock() 56 | self.wakeup = Condition() 57 | self.error = None 58 | self.pollingthread = None 59 | self.shutdown = False 60 | self.job = None 61 | self.checklockout = 0 62 | self.lastnonce = 0 63 | self.multiplier = 0 64 | 65 | try: 66 | 67 | # Listen for setup commands 68 | while True: 69 | data = self.rxconn.recv() 70 | 71 | if data[0] == "connect": break 72 | 73 | else: raise Exception("Unknown setup message: %s" % str(data)) 74 | 75 | # Connect to board and upload firmware if neccessary 76 | self.device = ZtexDevice(self, self.serial, self.takeover, self.firmware) 77 | 78 | # Configure clock 79 | self._set_multiplier(self.device.default_multiplier) 80 | 81 | # Start polling thread 82 | self.pollingthread = Thread(None, self.polling_thread, "polling_thread") 83 | self.pollingthread.daemon = True 84 | self.pollingthread.start() 85 | 86 | self.send("started_up") 87 | 88 | # Listen for commands 89 | while True: 90 | if self.error: raise self.error 91 | 92 | data = self.rxconn.recv() 93 | 94 | if data[0] == "shutdown": break 95 | 96 | elif data[0] == "ping": self.send("pong") 97 | 98 | elif data[0] == "pong": pass 99 | 100 | elif data[0] == "set_pollinterval": 101 | self.pollinterval = data[1] 102 | with self.wakeup: self.wakeup.notify() 103 | 104 | elif data[0] == "send_job": 105 | self.checklockout = time.time() + 1 106 | self.job = data[1] 107 | with self.wakeup: 108 | start = time.time() 109 | self.device.send_job(data[1][64:76] + data[2]) 110 | end = time.time() 111 | self.lastnonce = 0 112 | self.checklockout = end + 0.5 113 | self.respond(start, end) 114 | 115 | else: raise Exception("Unknown message: %s" % str(data)) 116 | 117 | except: self.log("Exception caught: %s" % traceback.format_exc(), 100, "r") 118 | finally: 119 | self.shutdown = True 120 | with self.wakeup: self.wakeup.notify() 121 | try: self.pollingthread.join(2) 122 | except: pass 123 | self.send("dying") 124 | 125 | 126 | def send(self, *args): 127 | with self.lock: self.txconn.send(args) 128 | 129 | 130 | def respond(self, *args): 131 | self.send("response", *args) 132 | 133 | 134 | def log(self, message, loglevel, format = ""): 135 | self.send("log", message, loglevel, format) 136 | 137 | 138 | def polling_thread(self): 139 | try: 140 | lastshares = [] 141 | errorcount = [0] * (self.device.maximum_multiplier + 1) 142 | errorweight = [0] * (self.device.maximum_multiplier + 1) 143 | maxerrorrate = [0] * (self.device.maximum_multiplier + 1) 144 | errorlimit = 0.05 145 | errorhysteresis = 0.1 146 | counter = 0 147 | 148 | while not self.shutdown: 149 | 150 | counter += 1 151 | 152 | # Poll for nonces 153 | now = time.time() 154 | nonces = self.device.read_nonces() 155 | exhausted = False 156 | with self.wakeup: 157 | if nonces[0][1] < self.lastnonce: 158 | self.lastnonce = nonces[0][1] 159 | exhausted = True 160 | if exhausted: self.send("keyspace_exhausted") 161 | for nonce in nonces: 162 | if nonce[0] != -self.device.nonce_offset and not nonce[0] in lastshares: 163 | if self.job: self.send("nonce_found", time.time(), struct.pack(" len(nonces): lastshares.pop(0) 166 | 167 | # Verify proper operation and adjust clocking if neccessary 168 | if now > self.checklockout and self.job: 169 | errorcount[self.multiplier] *= 0.995 170 | errorweight[self.multiplier] = errorweight[self.multiplier] * 0.995 + 1 171 | for nonce in nonces: 172 | invalid = True 173 | for offset in (0, 1, -1, 2, -2): 174 | hash = Job.calculate_hash(self.job[:76] + struct.pack(" 150 and maxerrorrate[limit + 1] < errorlimit: limit += 1 188 | multiplier = 0 189 | best = 0 190 | for i in range(limit + 1): 191 | effective = (i + 1 + (errorhysteresis if i == self.multiplier else 0)) * (1 - maxerrorrate[i]) 192 | if effective > best: 193 | best = effective 194 | multiplier = i 195 | self._set_multiplier(multiplier) 196 | 197 | if counter >= 10: 198 | counter = 0 199 | try: self.send("error_rate", errorcount[self.multiplier] / errorweight[self.multiplier]) 200 | except: pass 201 | 202 | with self.wakeup: self.wakeup.wait(self.pollinterval) 203 | 204 | except Exception as e: 205 | self.log("Exception caught: %s" % traceback.format_exc(), 100, "r") 206 | self.error = e 207 | # Unblock main thread 208 | self.send("ping") 209 | 210 | 211 | def _set_multiplier(self, multiplier): 212 | multiplier = min(max(multiplier, 1), self.device.maximum_multiplier) 213 | if multiplier == self.multiplier: return 214 | self.device.set_multiplier(multiplier) 215 | self.multiplier = multiplier 216 | self.checklockout = time.time() + 2 217 | self.send("speed_changed", (multiplier + 1) * self.device.base_frequency * self.device.hashes_per_clock) 218 | -------------------------------------------------------------------------------- /modules/theseven/ztex/driver.py: -------------------------------------------------------------------------------- 1 | # Modular Python Bitcoin Miner 2 | # Copyright (C) 2012 Michael Sparmann (TheSeven) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | # 18 | # Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you 19 | # want to support further development of the Modular Python Bitcoin Miner. 20 | 21 | 22 | 23 | ######################################### 24 | # ZTEX USB FPGA Module low level driver # 25 | ######################################### 26 | 27 | 28 | 29 | import time 30 | import usb 31 | import struct 32 | import traceback 33 | from array import array 34 | from threading import RLock 35 | 36 | 37 | 38 | class ZtexDevice(object): 39 | 40 | 41 | def __init__(self, proxy, serial, takeover, firmware): 42 | self.lock = RLock() 43 | self.proxy = proxy 44 | self.serial = serial 45 | self.takeover = takeover 46 | self.firmware = firmware 47 | self.handle = None 48 | permissionproblem = False 49 | deviceinuse = False 50 | for bus in usb.busses(): 51 | if self.handle != None: break 52 | for dev in bus.devices: 53 | if self.handle != None: break 54 | if dev.idVendor == 0x221a and dev.idProduct >= 0x100 and dev.idProduct <= 0x1ff: 55 | try: 56 | handle = dev.open() 57 | _serial = handle.getString(dev.iSerialNumber, 100).decode("latin1") 58 | if serial == "" or serial == _serial: 59 | try: 60 | if self.takeover: 61 | handle.reset() 62 | time.sleep(1) 63 | configuration = dev.configurations[0] 64 | interface = configuration.interfaces[0][0] 65 | handle.setConfiguration(configuration.value) 66 | handle.claimInterface(interface.interfaceNumber) 67 | handle.setAltInterface(interface.alternateSetting) 68 | self.handle = handle 69 | self.serial = _serial 70 | except: deviceinuse = True 71 | except: permissionproblem = True 72 | if self.handle == None: 73 | if deviceinuse: 74 | raise Exception("Can not open the specified device, possibly because it is already in use") 75 | if permissionproblem: 76 | raise Exception("Can not open the specified device, possibly due to insufficient permissions") 77 | raise Exception("Can not open the specified device") 78 | 79 | descriptor = array("B", self.handle.controlMsg(0xc0, 0x22, 40, 0, 0, 100)) 80 | if len(descriptor) != 40: raise Exception("Bad ZTEX descriptor length: %d" % len(descriptor)) 81 | size, version, magic = struct.unpack("<2BI", descriptor[:6]) 82 | product = struct.unpack("4B", descriptor[6:10]) 83 | fwversion, ifversion, = struct.unpack("2B", descriptor[10:12]) 84 | ifcaps = struct.unpack("6B", descriptor[12:18]) 85 | moduledata = struct.unpack("12B", descriptor[18:30]) 86 | sn = struct.unpack("10s", descriptor[30:])[0].decode("ascii") 87 | if size != 40: raise Exception("Bad ZTEX descriptor size: %d" % size) 88 | if version != 1: raise Exception("Bad ZTEX descriptor version: %d" % version) 89 | if magic != struct.unpack("= 0 and sig1 < sig2): raise Exception("Signature not found in bitstream, wrong bit order?") 125 | self.handle.controlMsg(0x40, 0x31, b"", 0, 0, 100) 126 | if self.hs_supported: 127 | ep, interface = struct.unpack("