17861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik#!/usr/bin/env python
27861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik# -*- coding: utf-8 -*-
37861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik#
47861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik# Copyright 2016 Google Inc.
57861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik#
67861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik# Licensed under the Apache License, Version 2.0 (the "License");
77861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik# you may not use this file except in compliance with the License.
87861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik# You may obtain a copy of the License at
97861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik#
107861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik#   http://www.apache.org/licenses/LICENSE-2.0
117861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik#
127861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik# Unless required by applicable law or agreed to in writing, software
137861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik# distributed under the License is distributed on an "AS IS" BASIS,
147861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
157861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik# See the License for the specific language governing permissions and
167861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik# limitations under the License.
177861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik#
187861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
197861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik"""
207861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    This module provides a vhal class which sends and receives messages to the vehicle HAL module
217861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    on an Android Auto device.  It uses port forwarding via ADB to communicted with the Android
227861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    device.
237861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
247861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    Example Usage:
257861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
267861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        import vhal_consts_1_0 as c
277861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        from vhal_emulator import Vhal
287861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
297861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Create an instance of vhal class.  Need to pass the vhal_types constants.
307861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        v = Vhal(c.vhal_types_1_0)
317861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
327861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Get the property config (if desired)
337861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        v.getConfig(c.VEHICLE_PROPERTY_HVAC_TEMPERATURE_SET)
347861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
357861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Get the response message to getConfig()
367861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        reply = v.rxMsg()
377861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        print reply
387861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
397861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Set left temperature to 70 degrees
407861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        v.setProperty(c.VEHICLE_PROPERTY_HVAC_TEMPERATURE_SET, c.VEHICLE_ZONE_ROW_1_LEFT, 70)
417861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
427861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Get the response message to setProperty()
437861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        reply = v.rxMsg()
447861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        print reply
457861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
467861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Get the left temperature value
477861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        v.getProperty(c.VEHICLE_PROPERTY_HVAC_TEMPERATURE_SET, c.VEHICLE_ZONE_ROW_1_LEFT)
487861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
497861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Get the response message to getProperty()
507861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        reply = v.rxMsg()
517861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        print reply
527861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
537861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    NOTE:  The rxMsg() is a blocking call, so it may be desirable to set up a separate RX thread
547861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            to handle any asynchronous messages coming from the device.
557861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
567861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    Example for creating RX thread (assumes vhal has already been instantiated):
577861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
587861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        from threading import Thread
597861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
607861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Define a simple thread that receives messags from a vhal object (v) and prints them
617861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        def rxThread(v):
627861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            while(1):
637861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik                print v.rxMsg()
647861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
657861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        rx = Thread(target=rxThread, args=(v,))
667861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        rx.start()
677861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
687861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    Protocol Buffer:
697861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        This module relies on VehicleHalProto_pb2.py being in sync with the protobuf in the VHAL.
707861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        If the VehicleHalProto.proto file has changed, re-generate the python version using:
717861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
727861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            protoc -I=<proto_dir> --python_out=<out_dir> <proto_dir>/VehicleHalProto.proto
737861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik"""
747861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
757861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik# Suppress .pyc files
767861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paikimport sys
777861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paiksys.dont_write_bytecode = True
787861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
797861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paikimport socket
807861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paikimport struct
817861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paikimport subprocess
827861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
837861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik# Generate the protobuf file from vendor/auto/embedded/lib/vehicle_hal:
847861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik#   protoc -I=proto --python_out=proto proto/VehicleHalProto.proto
857861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paikimport VehicleHalProto_pb2
867861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
877861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
887861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paikclass Vhal:
897861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    """
907861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        Dictionary of prop_id to value_type.  Used by setProperty() to properly format data.
917861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    """
927861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    _propToType = {}
937861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
947861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    ### Private Functions
957861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    def _txCmd(self, cmd):
967861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        """
977861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            Transmits a protobuf to Android Auto device.  Should not be called externally.
987861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        """
997861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Serialize the protobuf into a string
1007861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        msgStr = cmd.SerializeToString()
1017861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        msgLen = len(msgStr)
1027861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Convert the message length into int32 byte array
1037861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        msgHdr = struct.pack('!I', msgLen)
1047861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Send the message length first
1057861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        self.sock.send(msgHdr)
1067861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Then send the protobuf
1077861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        self.sock.send(msgStr)
1087861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
1097861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    ### Public Functions
1107861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    def printHex(self, data):
1117861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        """
1127861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            For debugging, print the protobuf message string in hex.
1137861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        """
1147861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        print "len = ", len(data), "str = ", ":".join("{:02x}".format(ord(d)) for d in data)
1157861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
1167861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    def openSocket(self):
1177861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        """
1187861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            Connects to an Android Auto device running a Vehicle HAL with simulator.
1197861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        """
1207861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Hard-coded socket port needs to match the one in DefaultVehicleHal
1217861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        portNumber = 33452
1227861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Setup ADB port forwarding
1237861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        subprocess.call("adb forward tcp:%d tcp:%d" % (portNumber, portNumber), shell=True)
1247861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Open the socket and connect
1257861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1267861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        self.sock.connect(('localhost', portNumber))
1277861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
1287861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    def rxMsg(self):
1297861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        """
1307861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            Receive a message over the socket.  This function blocks if a message is not available.
1317861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik              May want to wrap this function inside of an rx thread to also collect asynchronous
1327861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik              messages generated by the device.
1337861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        """
1347861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Receive the message length (int32) first
1357861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        b = self.sock.recv(4)
1367861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        if (len(b) == 4):
1377861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            msgLen, = struct.unpack('!I', b)
1387861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            if (msgLen > 0):
1397861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik                # Receive the actual message
1407861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik                b = self.sock.recv(msgLen)
1417861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik                if (len(b) == msgLen):
1427861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik                    # Unpack the protobuf
1437861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik                    msg = VehicleHalProto_pb2.EmulatorMessage()
1447861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik                    msg.ParseFromString(b)
1457861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik                    return msg
1467861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
1477861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    def getConfig(self, prop):
1487861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        """
1497861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            Sends a getConfig message for the specified property.
1507861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        """
1517861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        cmd = VehicleHalProto_pb2.EmulatorMessage()
1527861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        cmd.msg_type = VehicleHalProto_pb2.GET_CONFIG_CMD
1537861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        propGet = cmd.prop.add()
1547861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        propGet.prop = prop
1557861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        self._txCmd(cmd)
1567861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
1577861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    def getConfigAll(self):
1587861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        """
1597861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            Sends a getConfigAll message to the host.  This will return all configs avaialable.
1607861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        """
1617861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        cmd = VehicleHalProto_pb2.EmulatorMessage()
1627861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        cmd.msg_type = VehicleHalProto_pb2.GET_CONFIG_ALL_CMD
1637861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        self._txCmd(cmd)
1647861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
1657861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    def getProperty(self, prop, area_id):
1667861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        """
1677861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            Sends a getProperty command for the specified property ID and area ID.
1687861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        """
1697861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        cmd = VehicleHalProto_pb2.EmulatorMessage()
1707861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        cmd.msg_type = VehicleHalProto_pb2.GET_PROPERTY_CMD
1717861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        propGet = cmd.prop.add()
1727861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        propGet.prop = prop
1737861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        propGet.area_id = area_id
1747861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        self._txCmd(cmd)
1757861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
1767861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    def getPropertyAll(self):
1777861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        """
1787861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            Sends a getPropertyAll message to the host.  This will return all properties avaialable.
1797861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        """
1807861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        cmd = VehicleHalProto_pb2.EmulatorMessage()
1817861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        cmd.msg_type = VehicleHalProto_pb2.GET_PROPERTY_ALL_CMD
1827861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        self._txCmd(cmd)
1837861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
1847861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    def setProperty(self, prop, area_id, value):
1857861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        """
1867861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            Sends a setProperty command for the specified property ID, area ID, and value.
1877861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik              This function chooses the proper value field to populate based on the config for the
1887861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik              property.  It is the caller's responsibility to ensure the value data is the proper
1897861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik              type.
1907861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        """
1917861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        cmd = VehicleHalProto_pb2.EmulatorMessage()
1927861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        cmd.msg_type = VehicleHalProto_pb2.SET_PROPERTY_CMD
1937861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        propValue = cmd.value.add()
1947861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        propValue.prop = prop
1957861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Insert value into the proper area
1967861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        propValue.area_id = area_id
1977861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Determine the value_type and populate the correct value field in protoBuf
1987861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        try:
1997861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            valType = self._propToType[prop]
2007861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        except KeyError:
2017861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            raise ValueError('propId is invalid:', prop)
2027861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            return
2037861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        propValue.value_type = valType
2047861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        if valType in self._types.TYPE_STRING:
2057861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            propValue.string_value = value
2067861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        elif valType in self._types.TYPE_BYTES:
2077861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            propValue.bytes_value = value
2087861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        elif valType in self._types.TYPE_INT32:
2097861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            propValue.int32_values.append(value)
2107861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        elif valType in self._types.TYPE_INT64:
2117861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            propValue.int64_values.append(value)
2127861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        elif valType in self._types.TYPE_FLOAT:
2137861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            propValue.float_values.append(value)
2147861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        elif valType in self._types.TYPE_INT32S:
2157861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            propValue.int32_values.extend(value)
2167861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        elif valType in self._types.TYPE_FLOATS:
2177861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            propValue.float_values.extend(value)
2187861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        else:
2197861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            raise ValueError('value type not recognized:', valType)
2207861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            return
2217861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        self._txCmd(cmd)
2227861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
2237861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik    def __init__(self, types):
2247861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Save the list of types constants
2257861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        self._types = types
2267861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Open the socket
2277861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        self.openSocket()
2287861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Get the list of configs
2297861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        self.getConfigAll()
2307861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        msg = self.rxMsg()
2317861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        # Parse the list of configs to generate a dictionary of prop_id to type
2327861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik        for cfg in msg.config:
2337861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik            self._propToType[cfg.prop] = cfg.value_type
2347861f4ef37a73f8ef84c0a68b03a4fbf7d039d2cSteve Paik
235