Skip to content

rph usb driver for 0.1.0 #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: testing
Choose a base branch
from
Open
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
*~
*.log
*.pyc
usb
__pycache__
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, we should solve this in a way that still ignores the pyusb folder that could be placed in the root directory.
No idea how exactly gitignore works here, could be easiest to just rename your worker module to something else...

worker/fpgamining/firmware/*
config/*
Empty file added modules/rph/__init__.py
Empty file.
4 changes: 4 additions & 0 deletions modules/rph/usb/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .rphusbworker import rphUSBWorker
from .rphusbhotplug import rphUSBHotplugWorker

workerclasses = [rphUSBWorker, rphUSBHotplugWorker]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer class names to start with an uppercase letter.
What does look better to you? RphUsbWorker, RphUSBWorker or RPHUSBWorker? The last one would be most consistent with existing code, but I'm not sure if that kind of all-uppercase is a good idea generally.

183 changes: 183 additions & 0 deletions modules/rph/usb/boardproxy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# Modular Python Bitcoin Miner
# Copyright (C) 2012 Michael Sparmann (TheSeven)
# Copyright (C) 2011-2012 rphlx <rph@l0x.org>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you
# want to support further development of the Modular Python Bitcoin Miner.



###############################################################
# rph usb out of process board access dispatcher #
###############################################################



import time
import signal
import struct
import traceback
from threading import Thread, Condition, RLock
from multiprocessing import Process
from core.job import Job
from .driver import rphUSBDevice


class rphUSBBoardProxy(Process):


def __init__(self, rxconn, txconn, serial, takeover, firmware, pollinterval):
super(rphUSBBoardProxy, self).__init__()
self.rxconn = rxconn
self.txconn = txconn
self.serial = serial
self.takeover = takeover
self.firmware = firmware
self.pollinterval = pollinterval


def run(self):
signal.signal(signal.SIGINT, signal.SIG_IGN)
signal.signal(signal.SIGTERM, signal.SIG_IGN)
self.lock = RLock()
self.wakeup = Condition()
self.error = None
self.pollingthread = None
self.shutdown = False
self.job = None
self.checklockout = 0
self.lastnonce = 0
self.multiplier = 0

try:

# Listen for setup commands
while True:
data = self.rxconn.recv()

if data[0] == "connect": break

else: raise Exception("Unknown setup message: %s" % str(data))

# Connect to board and upload firmware if neccessary
self.device = rphUSBDevice(self, self.serial, self.takeover, self.firmware)

# Configure clock
#self._set_multiplier(192000000)
self.send("speed_changed", 16*192000000)

# Start polling thread
self.pollingthread = Thread(None, self.polling_thread, "polling_thread")
self.pollingthread.daemon = True
self.pollingthread.start()

self.send("started_up")

# Listen for commands
while True:
if self.error: raise self.error

data = self.rxconn.recv()

if data[0] == "shutdown": break

elif data[0] == "ping": self.send("pong")

elif data[0] == "pong": pass

elif data[0] == "set_pollinterval":
self.pollinterval = data[1]
with self.wakeup: self.wakeup.notify()

elif data[0] == "send_job":
self.checklockout = time.time() + 1
self.job = data[1]
with self.wakeup:
start = time.time()
self.device.send_job(data[2][::-1] + data[1][75:63:-1])
end = time.time()
self.lastnonce = 0
self.checklockout = end + 0.5
self.respond(start, end)

else: raise Exception("Unknown message: %s" % str(data))

except: self.log("Exception caught: %s" % traceback.format_exc(), 100, "r")
finally:
self.shutdown = True
with self.wakeup: self.wakeup.notify()
try: self.pollingthread.join(2)
except: pass
self.send("dying")


def send(self, *args):
with self.lock: self.txconn.send(args)


def respond(self, *args):
self.send("response", *args)


def log(self, message, loglevel, format = ""):
self.send("log", message, loglevel, format)


def polling_thread(self):
try:
lastshares = []
counter = 0

while not self.shutdown:
# Poll for nonces
now = time.time()
nonces = self.device.read_nonces()
exhausted = False
with self.wakeup:
if len(nonces) > 0 and nonces[0] < self.lastnonce:
self.lastnonce = nonces[0]
exhausted = True
if exhausted: self.send("keyspace_exhausted")
for nonce in nonces:
if not nonce[0] in lastshares:
if self.job: self.send("nonce_found", time.time(), struct.pack("<I", nonce[0]))
lastshares.append(nonce[0])
while len(lastshares) > len(nonces): lastshares.pop(0)

counter += 1
if counter >= 10:
counter = 0
# Read temperatures
temp = self.device.read_temps()
self.send("temperature_read", temp)

with self.wakeup: self.wakeup.wait(self.pollinterval)

except Exception as e:
self.log("Exception caught: %s" % traceback.format_exc(), 100, "r")
self.error = e
# Unblock main thread
self.send("ping")


def _set_multiplier(self, multiplier):
multiplier = min(max(multiplier, 1), self.device.maximum_multiplier)
if multiplier == self.multiplier: return
self.device.set_multiplier(multiplier)
self.multiplier = multiplier
self.checklockout = time.time() + 2
self.send("speed_changed", (multiplier + 1) * self.device.base_frequency * self.device.hashes_per_clock)
131 changes: 131 additions & 0 deletions modules/rph/usb/driver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# Modular Python Bitcoin Miner
# Copyright (C) 2012 Michael Sparmann (TheSeven)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# Please consider donating to 1PLAPWDejJPJnY2ppYCgtw5ko8G5Q4hPzh if you
# want to support further development of the Modular Python Bitcoin Miner.



#########################################
# rph usb level driver #
#########################################



import time
import usb
import struct
import traceback
from array import array
from threading import RLock
from binascii import hexlify, unhexlify



class rphUSBDevice(object):


def __init__(self, proxy, serial, takeover, firmware):
self.lock = RLock()
self.proxy = proxy
self.serial = serial
self.takeover = takeover
self.firmware = firmware
self.handle = None
self.rxdata = array("B")
permissionproblem = False
deviceinuse = False
for bus in usb.busses():
if self.handle != None: break
for dev in bus.devices:
if self.handle != None: break
if dev.idVendor == 0xf1f0:
try:
handle = dev.open()
_serial = hexlify(handle.controlMsg(0xc0, 0x96, 16, 0, 0, 100))
#_serial = "0" # handle.getString(dev.iSerialNumber, 100).decode("latin1")
if serial == "" or serial == _serial:
try:
if self.takeover:
handle.reset()
time.sleep(1)
configuration = dev.configurations[0]
interface = configuration.interfaces[0][0]
handle.setConfiguration(configuration.value)
handle.claimInterface(interface.interfaceNumber)
handle.setAltInterface(interface.alternateSetting)
self.handle = handle
self.serial = _serial
except: deviceinuse = True
except: permissionproblem = True
if self.handle == None:
if deviceinuse:
raise Exception("Can not open the specified device, possibly because it is already in use")
if permissionproblem:
raise Exception("Can not open the specified device, possibly due to insufficient permissions")
raise Exception("Can not open the specified device")


def set_multiplier(self, multiplier):
return None
#with self.lock:
# self.handle.controlMsg(0x40, 0x83, b"", multiplier, 0, 100)


def send_job(self, data):
with self.lock:
self.handle.controlMsg(0x40, 0x40, unhexlify("40") + data, 0, 0, 100)


def read_nonces(self):
with self.lock:
char = ''
try:
char = self.handle.controlMsg(0xc0, 0x41, 1, 0, 0, 100)
except:
time.sleep(0.01)
pass
if len(char):
self.rxdata = self.rxdata + char
nonces = []
if len(self.rxdata) >= 4:
golden = self.rxdata[0:4]
golden = golden[::-1]
golden = golden.tostring()
nonces.append(struct.unpack("<I", golden))
self.rxdata = array("B")
# for i in range(self.num_nonces):
# values = struct.unpack("<III", data[12 * i : 12 * (i + 1)])
# nonces.append((values[0] - self.nonce_offset, values[1] - self.nonce_offset, values[2]))
return nonces

def read_temps(self):
with self.lock:
rawtemp = ''
try:
self.handle.controlMsg(0x40, 0xe8, None, 0, 0, 100)
time.sleep(0.05)
rawtemp = self.handle.controlMsg(0xc0, 0xea, 2, 0, 0, 100)
except:
pass
if len(rawtemp) == 2:
temp = rawtemp[0] * 256 + rawtemp[1]
temp = 128.0 * temp / 32768.0
return (temp)
else:
return (0.0)

Loading