def __init__(self, type_prefix, name_prefix, device_class, common_group='monitor', get_revision_fields=None): """Initialize the generator. Args: type_prefix: A snake_case string to prefix each monitor structure type. name_prefix: A snake_case string to prefix each enum and function name. device_class: A device class that inherits DeviceConfigBase. common_group: Name of group containing all monitors. get_revision_fields: A function that returns an initialization string for extra fields in the revision map. Used by the analog monitors to initialize channel_map. """ self._type_prefix = c_helpers.SnakeToCamel(type_prefix) self._name_prefix = c_helpers.SnakeToCamel(name_prefix) self._device_class = device_class self._get_revision_fields = get_revision_fields self._groups = {} self._includes = [] return_true = lambda x: True self.CreateGroup(name=common_group, is_member_function=return_true)
def _GenerateTypeInfo(type_info, prefix): """Generate TypeInfo structures.""" fields = '' for path, field_type in _GetType(type_info.ctype): fields += textwrap.dedent("""\ {{".{prefix}.{path}", kDataType{type}, OFFSET_OF({name}, {path})}}, """).format(name=type_info.struct_name, prefix=prefix, path=path[1:], type=c_helpers.SnakeToCamel(field_type)) s = textwrap.dedent("""\ const TypeInfoField kTypeInfoField{struct_name}[] = {{ {fields} }}; const TypeInfo kTypeInfo{struct_name} = {{ reinterpret_cast<PackTypeFunction>({pack_func}), {pack_size}, reinterpret_cast<UnpackTypeFunction>({unpack_func}), {unpack_size}, ARRAYSIZE(kTypeInfoField{struct_name}), kTypeInfoField{struct_name} }}; """).format(fields=c_helpers.Indent(fields, 1)[:-1], struct_name=type_info.struct_name, pack_func=type_info.pack_func, pack_size=type_info.pack_size, unpack_func=type_info.unpack_func, unpack_size=type_info.unpack_size) return s
def _GenerateHeader(header_file): """Generate output header file.""" guard = re.sub('[/.]', '_', header_file).upper() + '_' data_types = sorted(['kDataType' + c_helpers.SnakeToCamel(s) for s in _TYPE_MAP.values()]) s = textwrap.dedent("""\ #ifndef {guard} #define {guard} #include <stddef.h> #include <stdint.h> #include "avionics/network/message_type.h" typedef size_t (*PackTypeFunction)(const void *in, size_t num, uint8_t *out); typedef size_t (*UnpackTypeFunction)(const uint8_t *in, size_t num, void *out); typedef enum {{ {data_types}, kNumDataTypes }} DataType; typedef struct {{ const char *path; DataType type; size_t offset; }} TypeInfoField; typedef struct {{ PackTypeFunction pack; size_t pack_size; UnpackTypeFunction unpack; size_t unpack_size; int32_t num_fields; const TypeInfoField *field; }} TypeInfo; template <typename T> const TypeInfo *GetTypeInfo(); const TypeInfo *GetCaptureHeaderTypeInfo(void); const TypeInfo *GetAioHeaderTypeInfo(void); const TypeInfo *GetMessageTypeInfo(MessageType message); void ConvertDataType(int64_t n, DataType src_type, size_t src_offset, size_t src_step, const void *src, DataType dst_type, size_t dst_offset, size_t dst_step, void *dst); #endif // {guard} """).format(guard=guard, data_types=c_helpers.Indent(',\n'.join(data_types))) return s
def JlinkProgramBootloaderElf(target_snake, hardware_type_snake, elf_file, speed=4000): """Program an elf_file bootloader on a node of hardware_type using Jlink.""" target_camel = c_helpers.SnakeToCamel(target_snake) hardware_type_camel = c_helpers.SnakeToCamel(hardware_type_snake) with tempfile.NamedTemporaryFile(suffix='.bin') as bin_file: node_info = { 'aio_node': target_camel, 'hardware_type': generate_image.hardware_type_helper.Name(hardware_type_camel) } assert (node_info['hardware_type'] in generate_image.hardware_type_helper.Names()) generate_image.GenerateBootloaderImage(node_info, elf_file, bin_file.name) return JlinkProgramBootloaderBin(bin_file.name, speed)
def __init__(self, config, expected_parameters): """Initialize the base class. Args: config: Specify a dict containing the per-device configuration. expected_parameters: Specify a list of keys to expect in config. """ self._config = copy.deepcopy(config) # Validate configuration. self._CheckExpectedParameters(self._config, expected_parameters) self._config['camel_name'] = c_helpers.SnakeToCamel(config.get('name')) self.ComputeParameters(self._config) self.CheckParameterValues(self._config)
def _GenerateEnum(self, name, members): """Generate common enum that describes the monitor outputs.""" enum_prefix = self._GetEnumPrefix(name) parts = [ textwrap.dedent("""\ typedef enum {{ k{enum_prefix}ForceSigned = -1,""").format(enum_prefix=enum_prefix) ] for value, name in enumerate(sorted(members)): parts.append(' k{enum_prefix}{name} = {value},'.format( enum_prefix=enum_prefix, name=c_helpers.SnakeToCamel(name), value=value)) parts.append( textwrap.dedent("""\ kNum{enum_prefix}s = {num} }} {enum_prefix}; """).format(enum_prefix=enum_prefix, num=len(members))) return '\n'.join(parts)
def GetGroupEnumValues(self, device): """Get group enumeration values for a particular device. See the analog monitors. The analog monitors defines groups 'input' and 'voltage'. This function creates a dict mapping 'input' and 'voltage' to the device's respective enumeration value for each type. Args: device: A device object that inherits DeviceConfigBase. Returns: A dict mapping each group name to an enumeration value. """ enum_values = {} for name, group in self._groups.iteritems(): prefix = 'k' + self._GetEnumPrefix(name) if self.IsDeviceInGroup(group, device): enum_values[name] = prefix + c_helpers.SnakeToCamel( device.GetName()) else: enum_values[name] = prefix + 'ForceSigned' # Not supported. return enum_values
def _GenerateParameterTypeInfo(module, name): """Generates TypeInfo for members of the 'parameters' group. These types are not required for hdf5_to_pcap, so no pack function, pack size, or unpack function are required. Args: module: Module that specifies the Python version of the type. name: Name of the type. Returns: String containing TypeInfo definitions. """ type_info = aio_message.GetInfoByModule(module, name) fields = '' for path, field_type in _GetType(type_info.ctype): fields += textwrap.dedent("""\ {{".{path}", kDataType{type}, OFFSET_OF({name}, {path})}}, """).format(name=type_info.struct_name, path=path[1:], type=c_helpers.SnakeToCamel(field_type)) return textwrap.dedent("""\ const TypeInfoField kTypeInfoField{struct_name}[] = {{ {fields} }}; const TypeInfo kTypeInfo{struct_name} = {{ reinterpret_cast<PackTypeFunction>(NULL), 0, reinterpret_cast<UnpackTypeFunction>(NULL), {unpack_size}, ARRAYSIZE(kTypeInfoField{struct_name}), kTypeInfoField{struct_name} }}; """).format(fields=c_helpers.Indent(fields, 1)[:-1], struct_name=type_info.struct_name, unpack_size=ctypes.sizeof(type_info.ctype))
def _WriteSwitchInfo(autogen_root, output_dir, script_name, config): """Write switch_info.c. Args: autogen_root: The MAKANI_HOME-equivalent top directory. output_dir: The directory in which to output the files. script_name: This script's filename. config: A NetworkConfig. Raises: IpAddressException: On any IP address error. SwitchMismatchException: If the TMS570 port of a switch is invalid. TrunkException: If there is a problem with the trunk configuration. """ file_without_extension = os.path.join(output_dir, 'switch_info') rel_path = os.path.relpath(file_without_extension, autogen_root) parts = [ textwrap.dedent(""" // Generated by {name}; do not edit. #include "{header}" #include <assert.h> #include <stdbool.h> #include <stdint.h> #include <string.h> """.format(name=script_name, header=rel_path + '.h')) ] ip_addr = {node.snake_name: node.ip_octet for node in config.aio_nodes} switches = config.GetSwitches() switches_sorted = sorted(switches.iterkeys()) message_types = config.all_messages def _GetTms570Node(switch): if 'config' not in switch or 'tms570' not in switch['config']: return None port = switch['ports'][switch['config']['tms570']] if not port.startswith('aio_nodes.'): raise SwitchMismatchException( 'No AIO node connected to TMS570 port.') return port[len('aio_nodes.'):] # The VLAN numbering convention here uses the lowest of the last octet of the # IP addresses of the TMS570s on the two connected switches, concatenated # with the port number on the associated switch. Since the core switches have # 27 ports we need 5 bits to represent the port number. As a consequence # TMS570s with last octets greater than 127 will present a problem for this # scheme. Additionally the IP with last octet 0 is reserved for other VLANs. def _GetSegId(node, port, remote_node, remote_port): ip = ip_addr[node] remote_ip = ip_addr[remote_node] if remote_ip < ip: ip = remote_ip port = remote_port if ip <= 0 or ip > 127: raise IpAddressException('Invalid IP octet 0 >= IP or IP > 127.') return (ip << 5) | int(port) def _GenerateMask(port_list): return sum(1 << i for i in port_list) path_finder = network_util.PathFinder(switches, None, network_c=True) net_c_forward = network_util.MakeNetworkCForwardingMap(path_finder) for switch_name in switches_sorted: switch = switches[switch_name] # We use simple configs for virtual or managed switches. if 'config' not in switch or 'tms570' not in switch['config']: continue config = switch['config'] node = _GetTms570Node(switch) seg_ids = [0] * config['chip']['num_ports'] for port, remote in switch['ports'].iteritems(): if remote.startswith('switches.'): _, remote_switch_name, remote_port = remote.split('.') remote_switch = switches[remote_switch_name] remote_node = _GetTms570Node(remote_switch) if not remote_node or remote_node not in ip_addr: continue seg_ids[int(port)] = _GetSegId(node, port, remote_node, remote_port) info = {} info['node_camel'] = c_helpers.SnakeToCamel(node) info['switch_type'] = 'kSwitchType' + c_helpers.SnakeToCamel( config['chip']['type']) info['segment_vlans'] = 'segmentVlanIds' + info['node_camel'] info['num_ports'] = config['chip']['num_ports'] info['num_fiber_ports'] = config['chip']['num_fiber_ports'] parts.append( textwrap.fill('static const uint16_t {}[{}] = {{{}}};'.format( info['segment_vlans'], info['num_ports'], ', '.join(str(i) for i in seg_ids)), 80, subsequent_indent=' ')) # Trunk configuration. trunk_ports = set() select_ports = set() trunk_unicast_learning_ports = set() info['num_multicast_overrides'] = 0 info['multicast_overrides'] = 'NULL' if 'trunk' in config: trunk_ports = config['trunk']['ports'] if 'unicast_learning' in config['trunk']: trunk_unicast_learning_ports = config['trunk'][ 'unicast_learning'] if 'override_message_routes' in config['trunk']: mcast_overrides = [] override = config['trunk']['override_message_routes'] for override_type, override_ports in override.iteritems(): mask = _GenerateMask(override_ports) for m in message_types: if m.name == override_type: if m.eop_message: mac = network_config.EopMessageTypeToEthernetAddress( eop_message_type.__dict__['kEopMessageType' + override_type]) elif m.winch_message: mac = network_config.WinchMessageTypeToEthernetAddress( winch_message_type.__dict__[ 'kWinchMessageType' + override_type]) else: mac = network_config.AioMessageTypeToEthernetAddress( message_type.__dict__['kMessageType' + override_type]) break else: raise TrunkException( 'Override contains invalid message type %s.' % override_type) mcast_overrides.append(('{%s}' % ', '.join( '0x%02X' % x for x in [mac.a, mac.b, mac.c, mac.d, mac.e, mac.f]), mask)) info['multicast_overrides'] = 'multicastOverrides' + info[ 'node_camel'] info['num_multicast_overrides'] = len(mcast_overrides) parts.append( 'static const TrunkMulticastOverride {}[{}] = {{\n{}\n}};'. format( info['multicast_overrides'], info['num_multicast_overrides'], ',\n'.join(' {%s, 0x%08X}' % o for o in mcast_overrides))) if 'select_default_ports' in config['trunk']: select_ports = config['trunk']['select_default_ports'] else: select_ports = trunk_ports info['forward_mask_a'] = _GenerateMask(config['network_a']) info['forward_mask_b'] = _GenerateMask(config['network_b']) info['forward_mask_c'] = net_c_forward[switch_name] info['egress_mask_c'] = _GenerateMask(config.get('network_c', [])) if 'isolate' in config: if trunk_ports: raise TrunkException( 'Isolate and trunk definitions are currently not ' 'supported together.') else: isolate_ports = config['isolate'] else: isolate_ports = trunk_ports info['isolate_mask'] = _GenerateMask(isolate_ports) info['trunk_mask'] = _GenerateMask(trunk_ports) info['unicast_learning_mask'] = _GenerateMask( trunk_unicast_learning_ports) info['select_default_mask'] = _GenerateMask(select_ports) info['unicast_mask'] = _GenerateMask(config['unicast']) info['host_port'] = config['tms570'] info['mirror_port'] = config['mirror'] parts.append( 'static const SwitchInfo switchInfo{node_camel} = {{\n' ' {switch_type}, {num_ports}, {num_fiber_ports},\n' ' {host_port}, {mirror_port},\n' ' 0x{forward_mask_a:X}, 0x{forward_mask_b:X},\n' ' 0x{forward_mask_c:X}, 0x{egress_mask_c:X},\n' ' 0x{isolate_mask:X}, 0x{unicast_mask:X}, {segment_vlans},\n' ' {{0x{trunk_mask:X}, 0x{select_default_mask:X},' ' 0x{unicast_learning_mask:X},\n' ' {num_multicast_overrides}, {multicast_overrides}}}\n' '}};\n'.format(**info)) parts.append( textwrap.dedent(""" const SwitchInfo *GetSwitchInfo(AioNode node) { switch (node) {"""[1:])) unused_nodes = set(c_helpers.EnumHelper('AioNode', aio_node).Names()) for switch_name in switches_sorted: switch = switches[switch_name] if 'config' not in switch or 'tms570' not in switch['config']: continue node = _GetTms570Node(switch) node_camel = c_helpers.SnakeToCamel(node) node_name = 'kAioNode' + node_camel unused_nodes.remove(node_name) parts.append(' case %s:' % node_name) if 'config' not in switch: parts.append(' assert(false);') parts.append(' return NULL;') else: parts.append(' return &switchInfo%s;' % node_camel) parts.append(' // Fall-through intentional.') for node in sorted(unused_nodes): parts.append(' case %s:' % node) parts.append( textwrap.dedent(""" case kAioNodeForceSigned: case kNumAioNodes: default: assert(false); return NULL; } } """[1:])) with open(file_without_extension + '.c', 'w') as f: f.write('\n'.join(parts))
def _GetEnumPrefix(self, name): return self._name_prefix + c_helpers.SnakeToCamel(name)