Esempio n. 1
0
    def testGetSkoobotsByName(self):
        """
        Test the getSkoobotsByName() method

        The method should return a list of (addr, name) tuples
        for all skoobots matching name
        """
        setUpRegistry = SkoobotRegistry(self.tempPath)
        names = (self.skooName, self.skooDupName, "nobody", None)
        for name in names:
            with self.subTest(name=name):
                skoobots = setUpRegistry.getSkoobotsByName(name)
                if name == self.skooDupName:
                    self.assertEqual(2, len(skoobots))
                    for skoobot in skoobots:
                        self.assertEqual(self.skooDupName, skoobot[1])
                    # Make a list of just the addresses
                    skooDupAddrs = [skoo[0] for skoo in skoobots]
                    self.assertIn(self.skooDupAddr1, skooDupAddrs)
                    self.assertIn(self.skooDupAddr2, skooDupAddrs)
                elif name == self.skooName:
                    self.assertEqual(1, len(skoobots))
                    # There is only 1 skoobot, so test it
                    skoobot = skoobots[0]
                    self.assertEqual(self.skooName, skoobot[1])
                    self.assertEqual(self.skooAddr, skoobot[0])
                else:
                    self.assertEqual(0, len(skoobots))
Esempio n. 2
0
    def testAddSkoobot(self):
        """
        Test addition of skoobots using the addSkoobot() method

        The method adds a skoobot to the registry using an address
        and an optional name.
        """
        registry = SkoobotRegistry(self.tempPath)
        namedAddr = "ff:ff:ff:ff:ff:ff"
        namedName = "newSkoobot"
        unnamedAddr = "ff:ff:ff:ff:ff:fe"

        with self.subTest("Add named Skoobot"):
            registry.addSkoobot(namedAddr, namedName)
            self.assertEqual(4, len(registry.registry))
            self.assertEqual(1, len(registry.getSkoobotsByAddress(namedAddr)))
            self.assertEqual(1, len(registry.getSkoobotsByName(namedName)))

        with self.subTest("Add unnamed Skoobot"):
            registry.addSkoobot(unnamedAddr)
            self.assertEqual(5, len(registry.registry))
            skoobots = registry.getSkoobotsByAddress(unnamedAddr)
            self.assertEqual(1, len(skoobots))
            self.assertIn(skoobots[0][1], registry.skoobotNames)

        with self.subTest("Add duplicate Skoobot"):
            # Bug #7: By default this replaces the existing
            # skoobot. If the replace=False parameter is set,
            # it raises a RuntimeError unless the parameters
            # are compatible with the existing entry.
            #
            # It is always true that it does not result in a
            # duplicate address.
            registry.addSkoobot(namedAddr, namedName)
            self.assertEqual(5, len(registry.registry))

            registry.addSkoobot(namedAddr, replace=False)
            self.assertEqual(5, len(registry.registry))

            with self.assertRaises(RuntimeError):
                registry.addSkoobot(unnamedAddr, namedName, replace=False)

        with self.subTest("Test invalid parameters"):
            with self.assertRaises(TypeError):
                registry.addSkoobot((namedAddr, namedName))

            with self.assertRaises(TypeError):
                registry.addSkoobot(namedAddr, (namedAddr, namedName))
Esempio n. 3
0
class SkoobotController:
    """
    Control API for Skoobots
    """
    def __init__(self):
        self.transport = TransportBluepy()
        self.registry = SkoobotRegistry()

        # Table of characteristic name to uuid mappings.
        # The characteristic names used are the ones in the firmware.
        self.uuids = {
            "cmd": "00001525-1212-efde-1523-785feabcd123",
            "data": "00001524-1212-efde-1523-785feabcd123",
            "byte2": "00001526-1212-efde-1523-785feabcd123",
            "byte128": "00001527-1212-efde-1523-785feabcd123",
            "byte4": "00001528-1212-efde-1523-785feabcd123",
        }
        self.connectedSkoobot = None

    def connect(self, name=None, addr=None):
        """
        Connect to the given Skoobot.
        If no Skoobot is given, connects to the default.
        Returns the address of the connected Skoobot if successful;
        None otherwise.
        """
        addrList = []

        if addr != None:
            if isinstance(addr, str):
                addrList.append(addr)
            else:
                raise TypeError("addr should be a string")
        else:
            if name == None:
                name = self.registry.getDefaultName()
            elif not isinstance(name, str):
                raise TypeError("name should be a string")
            if name != None:
                skoobots = self.registry.getSkoobotsByName(name)
                addrList = [bot[0] for bot in skoobots]
            else:
                raise RuntimeError("No default skoobot defined")

            if len(addrList) == 0:
                raise ValueError(
                    "No Skoobot with name {0:s} found".format(name))

        if self.connectedSkoobot != None:
            self.disconnect()

        for botAddr in addrList:
            try:
                self.transport.connect(botAddr)
                self.connectedSkoobot = botAddr
                break
            except BTLEException:
                pass

        return self.connectedSkoobot

    def disconnect(self):
        self.transport.disconnect()
        self.connectedSkoobot = None

    def sendCommand(self, data, waitForResponse=False):
        if self.connectedSkoobot == None:
            raise RuntimeError("BLE not connected")
        data = int(data)
        cmdBytes = data.to_bytes(1, byteorder="little")
        characteristics = self.transport.getRawCharacteristicsByUUID(
            self.uuids["cmd"])
        if len(characteristics) == 0:
            raise RuntimeError("cmd characteristic not supported by firmware")
        cmd = characteristics[0]
        cmd.write(cmdBytes, waitForResponse)

    def readBytes(self, charName="data"):
        """
        Read an array of bytes from the named characteristic

        returns a bytearray of the data
        """
        if self.connectedSkoobot == None:
            raise RuntimeError("BLE not connected")
        characteristics = self.transport.getRawCharacteristicsByUUID(
            self.uuids[charName])
        if len(characteristics) == 0:
            raise RuntimeError(
                "{0:s} characteristic not supported by firmware".format(
                    charName))
        charac = characteristics[0]
        dataBytes = charac.read()
        return dataBytes

    def readData(self, charName="data"):
        dataBytes = self.readBytes(charName)
        value = int.from_bytes(dataBytes, byteorder="little")
        return value

    def cmdRight(self):
        self.sendCommand(CMD_RIGHT, True)

    def cmdLeft(self):
        self.sendCommand(CMD_LEFT, True)

    def cmdForward(self):
        self.sendCommand(CMD_FORWARD, True)

    def cmdBackward(self):
        self.sendCommand(CMD_BACKWARD, True)

    def cmdStop(self):
        self.sendCommand(CMD_STOP, True)

    def cmdSleep(self):
        self.sendCommand(CMD_SLEEP, True)

    def cmdRoverMode(self):
        self.sendCommand(CMD_ROVER_MODE, True)

    def requestDistance(self):
        self.sendCommand(CMD_GET_DISTANCE, True)
        return self.readData()

    def requestAmbientLight(self):
        self.sendCommand(CMD_GET_AMBIENT, True)
        return self.readData("byte2")