# pylint: disable=import-error
#
# Raspdancer
#
# Implementation of the Facedancer API that supports direct access to the MAX324x
# chip via a RasPi's SoC SPI bus. Emulates talking to a Facedancer, but ignores
# the details of the GreatFET protocol.
#
import os
import sys
import time
from ..core import FacedancerApp
from ..backends.MAXUSBApp import MAXUSBApp
from ..logging import log
[docs]
class RaspdancerMaxUSBApp(MAXUSBApp):
app_name = "MAXUSB"
app_num = 0x00 # Not meaningful for us. TODO: Remove!
[docs]
@classmethod
def appropriate_for_environment(cls, backend_name):
"""
Determines if the current environment seems appropriate
for using the GoodFET::MaxUSB backend.
"""
# Only ever try Raspdancer backends if the backend is set to raspdancer;
# we don't want to start randomly spamming a system's SPI bus.
if backend_name is None or backend_name != "raspdancer":
return False
# If we're not explicitly trying to use something else,
# see if there's a connected Raspdancer.
try:
rd = Raspdancer()
return True
except ImportError as e:
log.info("Skipping Raspdancer devices, as perquisites aren't installed ({}).".format(e))
return False
except:
return False
def __init__(self, device=None, verbose=0, quirks=None):
if device is None:
device = Raspdancer(verbose=verbose)
FacedancerApp.__init__(self, device, verbose)
self.connected_device = None
self.enable()
if verbose > 0:
rev = self.read_register(self.reg_revision)
print(self.app_name, "revision", rev)
# set duplex and negative INT level (from GoodFEDMAXUSB.py)
self.write_register(self.reg_pin_control,
self.full_duplex | self.interrupt_level)
[docs]
def init_commands(self):
pass
[docs]
def enable(self):
for i in range(3):
self.device.set_up_comms()
if self.verbose > 0:
print(self.app_name, "enabled")
[docs]
def ack_status_stage(self, blocking=False):
if self.verbose > 5:
print(self.app_name, "sending ack!")
self.device.transfer(b'\x01')
[docs]
def read_register(self, reg_num, ack=False):
if self.verbose > 1:
print(self.app_name, "reading register 0x%02x" % reg_num)
data = bytearray([ reg_num << 3, 0 ])
if ack:
data[0] |= 1
resp = self.device.transfer(data)
if self.verbose > 2:
print(self.app_name, "read register 0x%02x has value 0x%02x" %
(reg_num, resp[1]))
return resp[1]
[docs]
def write_register(self, reg_num, value, ack=False):
if self.verbose > 2:
print(self.app_name, "writing register 0x%02x with value 0x%02x" %
(reg_num, value))
data = bytearray([ (reg_num << 3) | 2, value ])
if ack:
data[0] |= 1
self.device.transfer(data)
[docs]
def read_bytes(self, reg, n):
if self.verbose > 2:
print(self.app_name, "reading", n, "bytes from register", reg)
data = bytes([ (reg << 3) ] + ([0] * n))
resp = self.device.transfer(data)
if self.verbose > 3:
print(self.app_name, "read", len(resp) - 1, "bytes from register", reg)
return resp[1:]
[docs]
def write_bytes(self, reg, data):
data = bytes([ (reg << 3) | 3 ]) + data
self.device.transfer(data)
if self.verbose > 3:
print(self.app_name, "wrote", len(data) - 1, "bytes to register", reg)
[docs]
class Raspdancer(object):
"""
Extended version of the Facedancer class that accepts a direct
SPI connection to the MAX324x chip, as used by the Raspdancer.
"""
[docs]
def __init__(self, verbose=0):
"""
Initializes our connection to the MAXUSB device.
"""
import spi
import RPi.GPIO as GPIO
self.verbose = verbose
self.buffered_result = b''
self.last_verb = -1
self.spi = spi
self.gpio = GPIO
self.gpio.setwarnings(False)
self.gpio.setmode(self.gpio.BOARD)
self.reset()
[docs]
def reset(self):
"""
Resets the connected MAXUSB chip.
"""
self.gpio.setup(15, self.gpio.OUT)
self.gpio.output(15, self.gpio.LOW)
self.gpio.output(15, self.gpio.HIGH)
[docs]
def set_up_comms(self):
"""
Sets up the Raspdancer to communicate with the MAX324x.
"""
# pin15=GPIO22 is linked to MAX3420 -RST
self.gpio.setup(15, self.gpio.OUT)
self.gpio.output(15,self.gpio.LOW)
self.gpio.output(15,self.gpio.HIGH)
self.spi.openSPI(speed=26000000)
[docs]
def transfer(self, data):
"""
Emulate the facedancer's write command, which blasts data
directly over to the SPI bus.
"""
if isinstance(data,str):
data = [ord(x) for x in data]
data = tuple(data)
data = self.spi.transfer(data)
return bytearray(data)