Esempio n. 1
0
 async def request_heartbeats(self):
     """Request heartbeats on a regular basis."""
     await self._ready.wait()
     while not self.transport.is_closing():
         await asyncio.sleep(self.HEARTBEAT_DELAY_MS / 1000,
                             loop=self.event_loop)
         hm.send(self.transport, hm.make_heartbeat_request())
Esempio n. 2
0
def identify_smart_sensors(serial_conns):
    """
    Given a list of serial port connections, figure out which
    contain smart sensors.

    Returns:
        A map of serial port names to UIDs.
    """
    def recv_subscription_response(conn, uid_queue, stop_event):
        """
        Place received subscription response UIDs from CONN into UID_QUEUE,
        stopping when STOP_EVENT is set.
        """
        try:
            for packet in hm.blocking_read_generator(conn, stop_event):
                msg_type = packet.get_message_id()
                if msg_type == hm.MESSAGE_TYPES["SubscriptionResponse"]:
                    _, _, uid = hm.parse_subscription_response(packet)
                    uid_queue.put(uid)
        except serial.SerialException:
            pass

    device_map = {}
    candidates = []
    for conn in serial_conns:
        old_timeout = conn.write_timeout
        conn.write_timeout = IDENTIFY_TIMEOUT
        try:
            hm.send(conn, hm.make_ping())
        except serial.SerialTimeoutException:
            continue
        finally:
            conn.write_timeout = old_timeout
        maybe_device = namedtuple("MaybeDevice",
                                  ["serial_conn", "queue", "event", "thread"])
        maybe_device.queue = queue.Queue()
        maybe_device.event = threading.Event()
        maybe_device.serial_conn = conn
        maybe_device.thread = threading.Thread(
            target=recv_subscription_response,
            args=(conn, maybe_device.queue, maybe_device.event))
        candidates.append(maybe_device)
    for cand in candidates:
        cand.thread.start()
    for cand in candidates:
        try:
            uid = cand.queue.get(block=True, timeout=IDENTIFY_TIMEOUT)
            device_map[cand.serial_conn.name] = uid
            # Shut device up
            hm.send(cand.serial_conn, hm.make_subscription_request(uid, [], 0))
        except queue.Empty:
            pass
    for cand in candidates:
        cand.event.set()
        cand.thread.join()
    return device_map
Esempio n. 3
0
    def handleOutput(self, n):
        """Processes the next n packets, or the number of packets, whichever 
        is smaller, in the sendBuffer queue. 

        sendBuffer should have tuples of (serial, packet)
        """

        for _ in range(n):
            if self.sendBuffer.empty():
                break
            serial, packet = self.sendBuffer.get()
            hm.send(serial, packet)
Esempio n. 4
0
 def _process_sub_request(self, msg):
     """Respond to a subscription request with an appropriate response."""
     self.update_time = time.time()
     dev_id = hm.uid_to_device_id(self.uid)
     self.verbose_log("Subscription request received")
     params, delay = struct.unpack("<HH", msg.get_payload())
     subscribed_params = hm.decode_params(dev_id, params)
     hm.send(
         self.transport,
         hm.make_subscription_response(dev_id, subscribed_params, delay,
                                       self.uid))
     self.delay = delay
     self.subscribed_params.update(set(subscribed_params))
Esempio n. 5
0
    def _process_device_read(self, msg):
        self.verbose_log("Device read received")
        device_id = hm.uid_to_device_id(self.uid)
        # Send a device data with the requested param and value tuples
        params, = struct.unpack("<H", msg.get_payload())
        read_params = hm.decode_params(device_id, params)
        read_data = []

        for param in read_params:
            if not (hm.readable(device_id, param)
                    and param in self.param_values):
                raise ValueError(
                    "Tried to read unreadable parameter {}".format(param))
            read_data.append((param, self.param_values[param]))
        hm.send(self.transport, hm.make_device_data(device_id, read_data))
 def test_read_device_data(self):
     """ Check that DeviceData packets are received and decoded. """
     start_time = time.time()
     hibike_message.send(
         self.dummy_device,
         hibike_message.make_subscription_request(self.dummy_dev_id,
                                                  self.dummy_params, 40))
     for packet in hibike_message.blocking_read_generator(
             self.dummy_device):
         if packet.get_message_id(
         ) == hibike_message.MESSAGE_TYPES["DeviceData"]:
             return
         self.assertLessEqual(
             time.time() - start_time, self.STOP_TIMEOUT,
             "did not read DeviceData packet before timeout")
 def test_stop_event(self):
     """
     Make sure that triggering the stop event prevents
     additional reads
     """
     hibike_message.send(
         self.dummy_device,
         hibike_message.make_subscription_request(self.dummy_dev_id,
                                                  self.dummy_params, 40))
     start_time = time.time()
     stop_event = threading.Event()
     for _ in hibike_message.blocking_read_generator(
             self.dummy_device, stop_event):
         stop_event.set()
         self.assertLessEqual(
             time.time() - start_time, self.STOP_TIMEOUT,
             "blocking_read_generator didn't stop when stop_event triggered"
         )
Esempio n. 8
0
    def _process_device_write(self, msg):
        # Write to requested parameters
        # and return the values of the parameters written to using a device data
        self.verbose_log("Device write received")
        device_id = hm.uid_to_device_id(self.uid)
        write_params_and_values = hm.decode_device_write(msg, device_id)

        for (param, value) in write_params_and_values:
            if not (hm.writable(device_id, param)
                    and param in self.param_values):
                raise ValueError(
                    "Tried to write read-only parameter: {}".format(param))
            self.param_values[param] = value

        updated_params = []
        for (param, value) in write_params_and_values:
            if hm.readable(device_id, param):
                updated_params.append((param, value))
        hm.send(self.transport, hm.make_device_data(device_id, updated_params))
Esempio n. 9
0
 async def send_subscribed_params(self):
     """Send values of subscribed parameters at a regular interval."""
     await self._ready.wait()
     device_id = hm.uid_to_device_id(self.uid)
     while not self.transport.is_closing():
         await asyncio.sleep(0.005, loop=self.event_loop)
         if self.update_time != 0 and self.delay != 0:
             if time.time() - self.update_time >= self.delay * 0.001:
                 # If the time equal to the delay has elapsed since the previous device data,
                 # send a device data with the device id
                 # and the device's subscribed params and values
                 data = []
                 for param in self.subscribed_params:
                     data.append((param, self.param_values[param]))
                 hm.send(self.transport,
                         hm.make_device_data(device_id, data))
                 self.update_time = time.time()
                 self.verbose_log("Regular data update sent from {}",
                                  hm.uid_to_device_name(self.uid))
Esempio n. 10
0
def device_write_thread(ser, queue):
    while True:
        instruction, args = queue.get()

        if instruction == "ping":
            hm.send(ser, hm.make_ping())
        elif instruction == "subscribe":
            uid, delay, params = args
            hm.send(
                ser,
                hm.make_subscription_request(hm.uid_to_device_id(uid), params,
                                             delay))
        elif instruction == "read":
            uid, params = args
            hm.send(ser, hm.make_device_read(hm.uid_to_device_id(uid), params))
        elif instruction == "write":
            uid, params_and_values = args
            hm.send(
                ser,
                hm.make_device_write(hm.uid_to_device_id(uid),
                                     params_and_values))
Esempio n. 11
0
 async def register_sensor(self, event_loop, devices, pending):
     """
     Try to get our UID from the sensor and register it with `hibike_process`.
     """
     await self._ready.wait()
     hm.send(self.transport, hm.make_ping())
     await asyncio.sleep(IDENTIFY_TIMEOUT, loop=event_loop)
     if self.uid is None:
         self.quit()
     else:
         hm.send(self.transport, hm.make_ping())
         hm.send(
             self.transport,
             hm.make_subscription_request(hm.uid_to_device_id(self.uid), [],
                                          0))
         devices[self.uid] = self
     pending.remove(self.transport.serial.name)
Esempio n. 12
0
    subscribed_params = []
    params_and_values = [("pot0", 6.7), ("pot1", 5.5), ("pot2", 34.1),
                         ("pot3", 0.15)]
if device == "YogiBear":
    subscribed_params = []
    params_and_values = [("duty", 20), ("forward", False)]

while (True):
    if (updateTime != 0 and delay != 0):
        if ((time.time() - updateTime) >= (delay * 0.001)):
            #If the time equal to the delay has elapsed since the previous device data, send a device data with the device id and the device's subscribed params and values
            data = [
                data_tuple for data_tuple in params_and_values
                if data_tuple[0] in subscribed_params
            ]
            hm.send(conn, hm.make_device_data(device_id, data))
            updateTime = time.time()
            print("Regular data update sent from %s" % device)

    msg = hm.read(conn)
    if not msg:
        time.sleep(.005)
        continue
    if msg.getmessageID() in [hm.messageTypes["SubscriptionRequest"]]:
        #Update the delay, subscription time, and params, then send a subscription response
        print("Subscription request recieved")
        params, delay = struct.unpack("<HH", msg.getPayload())

        subscribed_params = hm.decode_params(device_id, params)
        hm.send(
            conn,
Esempio n. 13
0
from hibike import Hibike
import hibike_message as hm
import time
import pdb
import binascii

h = Hibike()
hm.send(h.serialToUID.values()[0][1], hm.make_sub_request(0))

# devices = h.getUIDs()
# pdb.set_trace()

# while 1:
# 	val = input("enter servo value: ")
# 	if val == -1:
# 		break
# 	c.writeValue(device.uid, "servo0", int(val))
# 	time.sleep(0.2)
# 	print(c.getData(device.uid, "servo0"))
Esempio n. 14
0
    def __repr__(self):
        res = ""
        res += hm.uid_to_device_name(self.uid)
        res += ":\n"
        res += "    %d" % self.uid
        res += "    %s\n" % self.serial_port.port
        res += "    %s\n" % self.data
        return res


SERIALS = [serial.Serial(port, 115200) for port in PORTS]
DEVICES = []

for s in SERIALS:
    hm.send(s, hm.make_ping())

while SERIALS:
    remaining = []
    for s in SERIALS:
        reading = hm.blocking_read(s)
        if reading:
            params, delay, device_type, year, id = struct.unpack(
                "<HHHBQ", reading.get_payload())
            uid = (device_type << 72) | (year << 64) | id
            DEVICES.append(HibikeDevice(s, params, delay, uid))
        else:
            remaining.append(s)
    SERIALS = remaining

print("devices:", DEVICES)
 def encode_packet(packet):
     """ Turn a HibikeMessage into an encoded packet. """
     fake_port = FakeSerialPort()
     hibike_message.send(fake_port, packet)
     return fake_port.drain()
Esempio n. 16
0
def main():
    """
    Create virtual devices and send test data on them.
    """
    parser = argparse.ArgumentParser()
    parser.add_argument('-d', '--device', required=True, help='device type')
    parser.add_argument('-p', '--port', required=True, help='serial port')
    parser.add_argument(
        '-v',
        '--verbose',
        help='print messages when sending and receiving packets',
        action="store_true")
    args = parser.parse_args()

    def verbose_log(fmt_string, *fmt_args):
        """
        Log a message using a formatting string if verbosity
        is enabled.
        """
        if args.verbose:
            print(fmt_string.format(*fmt_args))

    device = args.device
    port = args.port
    verbose_log("Device {} on port {}", device, port)
    conn = serial.Serial(port, 115200)

    for device_num in hm.DEVICES:
        if hm.DEVICES[device_num]["name"] == device:
            device_id = device_num
            break
    else:
        raise RuntimeError("Invalid Device Name!!!")

    year = 1
    randomness = random.randint(0, 0xFFFFFFFFFFFFFFFF)
    delay = 0
    update_time = 0
    uid = (device_id << 72) | (year << 64) | randomness

    # Here, the parameters and values to be sent in device datas
    # are set for each device type, the list of subscribed parameters is set to empty,
    if device == "LimitSwitch":
        subscribed_params = []
        params_and_values = [("switch0", True), ("switch1", True),
                             ("switch2", False), ("switch3", False)]
    if device == "ServoControl":
        subscribed_params = []
        params_and_values = [("servo0", 2), ("enable0", True), ("servo1", 0),
                             ("enable1", True), ("servo2", 5),
                             ("enable2", True), ("servo3", 3),
                             ("enable3", False)]
    if device == "Potentiometer":
        subscribed_params = []
        params_and_values = [("pot0", 6.7), ("pot1", 5.5), ("pot2", 34.1),
                             ("pot3", 0.15)]
    if device == "YogiBear":
        subscribed_params = []
        params_and_values = [("enable", True), ("command_state", 1),
                             ("duty_cycle", 1.0), ("pid_pos_setpoint", 2.0),
                             ("pid_pos_kp", 3.0), ("pid_pos_ki", 4.0),
                             ("pid_pos_kd", 5.0), ("pid_vel_setpoint", 6.0),
                             ("pid_vel_kp", 7.0), ("pid_vel_ki", 8.0),
                             ("pid_vel_kd", 9.0), ("current_thresh", 10.0),
                             ("enc_pos", 11.0), ("enc_vel", 12.0),
                             ("motor_current", 13.0), ("deadband", 0.5)]
    if device == "RFID":
        subscribed_params = []
        params_and_values = [("id", 0), ("tag_detect", 0)]
    if device == "BatteryBuzzer":
        subscribed_params = []
        params_and_values = [("is_unsafe", False), ("calibrated", True),
                             ("v_cell1", 11.0), ("v_cell2", 11.0),
                             ("v_cell3", 11.0), ("v_batt", 11.0),
                             ("dv_cell2", 11.0), ("dv_cell3", 11.0)]
    if device == "LineFollower":
        subscribed_params = []
        params_and_values = [("left", 1.0), ("center", 1.0), ("right", 1.0)]

    while True:
        if update_time != 0 and delay != 0:
            if time.time() - update_time >= delay * 0.001:
                # If the time equal to the delay has elapsed since the previous device data,
                # send a device data with the device id
                # and the device's subscribed params and values
                data = []
                for data_tuple in params_and_values:
                    if data_tuple[0] in subscribed_params and hm.readable(
                            device_id, data_tuple[0]):
                        data.append(data_tuple)
                hm.send(conn, hm.make_device_data(device_id, data))
                update_time = time.time()
                verbose_log("Regular data update sent from {}", device)

        msg = hm.read(conn)
        if not msg:
            time.sleep(.005)
            continue
        if msg.get_message_id() in [hm.MESSAGE_TYPES["SubscriptionRequest"]]:
            # Update the delay, subscription time,
            # and params, then send a subscription response
            verbose_log("Subscription request received")
            params, delay = struct.unpack("<HH", msg.get_payload())

            subscribed_params = hm.decode_params(device_id, params)
            hm.send(
                conn,
                hm.make_subscription_response(device_id, subscribed_params,
                                              delay, uid))
            update_time = time.time()
        if msg.get_message_id() in [hm.MESSAGE_TYPES["Ping"]]:
            # Send a subscription response
            verbose_log("Ping received")
            hm.send(
                conn,
                hm.make_subscription_response(device_id, subscribed_params,
                                              delay, uid))
        if msg.get_message_id() in [hm.MESSAGE_TYPES["DeviceRead"]]:
            # Send a device data with the requested param and value tuples
            verbose_log("Device read received")
            params = struct.unpack("<H", msg.get_payload())
            read_params = hm.decode_params(device_id, params)
            read_data = []

            for data_tuple in params_and_values:
                if data_tuple[0] in read_params:
                    if not hm.readable(device_id, data_tuple[0]):
                        # Raise a syntax error if one of the values to be read is not readable
                        raise SyntaxError(
                            "Attempted to read an unreadable value")
                    read_data.append(data_tuple)
            hm.send(conn, hm.make_device_data(device_id, read_data))

        if msg.get_message_id() in [hm.MESSAGE_TYPES["DeviceWrite"]]:
            # Write to requested parameters
            # and return the values of the parameters written to using a device data
            verbose_log("Device write received")
            write_params_and_values = hm.decode_device_write(msg, device_id)
            write_params = [
                param_val[0] for param_val in write_params_and_values
            ]
            value_types = [
                hm.PARAM_MAP[device_id][name][1] for name in write_params
            ]

            write_tuples = []
            # pylint: disable=consider-using-enumerate
            for index in range(len(write_params)):
                write_tuples.append(
                    (write_params[index], write_params_and_values[index][1]))
            for new_tuple in write_tuples:
                if not hm.writable(device_id, new_tuple[0]):
                    # Raise a syntax error if the value
                    # that the message attempted to write to is not writable
                    raise SyntaxError(
                        "Attempted to write to an unwritable value")
                params_and_values[hm.PARAM_MAP[device_id][new_tuple[0]]
                                  [0]] = new_tuple

            # Send the written data, make sure you only send data for readable parameters
            index = 0
            while index < len(write_params):
                if hm.readable(device_id, write_tuples[index][0]):
                    index += 1
                else:
                    del write_tuples[index]
            hm.send(conn, hm.make_device_data(device_id, write_tuples))
Esempio n. 17
0
def device_write_thread(ser, instr_queue):
    """
    Send packets to SER based on instructions from INSTR_QUEUE.
    """
    try:
        while True:
            instruction, args = instr_queue.get()

            if instruction == "ping":
                hm.send(ser, hm.make_ping())
            elif instruction == "subscribe":
                uid, delay, params = args
                hm.send(
                    ser,
                    hm.make_subscription_request(hm.uid_to_device_id(uid),
                                                 params, delay))
            elif instruction == "read":
                uid, params = args
                hm.send(ser,
                        hm.make_device_read(hm.uid_to_device_id(uid), params))
            elif instruction == "write":
                uid, params_and_values = args
                hm.send(
                    ser,
                    hm.make_device_write(hm.uid_to_device_id(uid),
                                         params_and_values))
            elif instruction == "disable":
                hm.send(ser, hm.make_disable())
            elif instruction == "heartResp":
                uid = args[0]
                hm.send(ser, hm.make_heartbeat_response())
    except serial.SerialException:
        # Device has disconnected
        pass
Esempio n. 18
0
 def _process_ping(self, msg):
     """Respond to a ping packet."""
     self.verbose_log("Ping received")
     dev_id = hm.uid_to_device_id(self.uid)
     hm.send(self.transport,
             hm.make_subscription_response(dev_id, [], 0, self.uid))
Esempio n. 19
0
 async def send_messages(self):
     """
     Send messages in the queue to the sensor.
     """
     await self._ready.wait()
     while not self.transport.is_closing():
         instruction, args = await self.write_queue.get()
         if instruction == "ping":
             hm.send(self.transport, hm.make_ping())
         elif instruction == "subscribe":
             uid, delay, params = args
             hm.send(
                 self.transport,
                 hm.make_subscription_request(hm.uid_to_device_id(uid),
                                              params, delay))
         elif instruction == "read":
             uid, params = args
             hm.send(self.transport,
                     hm.make_device_read(hm.uid_to_device_id(uid), params))
         elif instruction == "write":
             uid, params_and_values = args
             hm.send(
                 self.transport,
                 hm.make_device_write(hm.uid_to_device_id(uid),
                                      params_and_values))
         elif instruction == "disable":
             hm.send(self.transport, hm.make_disable())
         elif instruction == "heartResp":
             uid = args[0]
             hm.send(self.transport,
                     hm.make_heartbeat_response(self.read_queue.qsize()))