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 _GenerateGetMessageTypeInfo(): """Generate accessor functions for the message type TypeInfo structures.""" info_map = aio_message.GetMessageInfoMapByNetworkFile() supported_types = {k: v for k, v in info_map.iteritems() if v} unsupported_types = [k for k, v in info_map.iteritems() if not v] s = textwrap.dedent("""\ const TypeInfo *GetMessageTypeInfo(MessageType message) { switch (message) { """) for message, info in supported_types.iteritems(): s += c_helpers.Indent(textwrap.dedent("""\ case {enum_name}: return &kTypeInfo{struct_name}; """).format(enum_name=message.enum_name, struct_name=info.struct_name), 2) for message in unsupported_types: s += c_helpers.Indent(textwrap.dedent("""\ case {enum_name}: return nullptr; // Not supported. """).format(enum_name=message.enum_name), 2) s += textwrap.dedent("""\ case kNumMessageTypes: default: return nullptr; } } """) # GCC 6.3, differently than GCC 4.8, treats type-assignments as equal types, # so generating functions with equivalent types result in redefinition error. # Therefore we have to identify unique types not from names but from the # actual type definition. unique_types = set() for v in supported_types.values(): struct_name = v.struct_name if v.ctype in unique_types: continue unique_types.add(v.ctype) s += textwrap.dedent("""\ template<> const TypeInfo *GetTypeInfo<{struct_name}>() {{ return &kTypeInfo{struct_name}; }} """).format(struct_name=struct_name) 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 _LinksToStrings(name, links): if links: strings = [ textwrap.dedent("""\ static const SwitchLinkInfo {name}[] = {{""".format(name=name)) ] entries = ', '.join([_LinkToString(link) for link in links]) strings += [c_helpers.Indent(entries)] strings += ['};\n'] return strings, name return [], 'NULL'
def _GenerateConfigDeviceText(self, path, revision, config_ref_by_text): """Helper function for GenerateMapByAddress. Args: path: A list of pack2 enum names describing the configuration type. revision: A dict describing the source code associated with this revision. config_ref_by_text: A dict mapping the source code initialization to variable reference. This function updates this map. Returns: A tuple containing the source code initialization for config and device structures. """ # Parts in output. config_parts = [] device_parts = [] # Generate config structure for each device. addresses = revision['text_by_address'].keys() for config_index, address in enumerate(addresses): num_configs = len(revision['devices_by_address'][address]) # If config_text exists in config_ref_by_text, do not duplicate. config_text = revision['text_by_address'][address] if config_text in config_ref_by_text: config_ref = config_ref_by_text[config_text] else: config_ref = 'kConfig{}Address0x{:02X}'.format( self._PathToString(path), address) config_ref_by_text[config_text] = config_ref config_parts.append( textwrap.dedent("""\ static const {type_prefix}MonitorConfig {ref}[{num}] = {{ {text}}}; """).format(type_prefix=self._type_prefix, ref=config_ref, text=c_helpers.Indent(config_text), num=num_configs)) # Generate device text using remapped config_ref such to eliminate # redundent device structures. device_parts.append( textwrap.dedent("""\ [{config_index}] = {{ .config = {config_ref}, .num_configs = {num_configs}}}, """).format(config_index=config_index, config_ref=config_ref, num_configs=num_configs)) return (config_parts, device_parts)
def _GenerateRevisionMapRecursive(self, path, device_ref_by_path, revision_key): """Generate map recursively for all revision paths.""" parts = ['{'] if len(path) == len(self._enum_path): revision = self._revision_by_path.get(tuple(path)) if revision: populated = self._GetPopulated(revision) device_ref = device_ref_by_path[tuple(path)] num_devices = len(revision[revision_key]) devices = revision['devices'] else: populated = 0 device_ref = 'NULL' num_devices = 0 devices = [] if self._get_revision_fields: parts.append( c_helpers.Indent(self._get_revision_fields(devices))) parts.append( c_helpers.Indent( textwrap.dedent("""\ .populated = 0x{populated:08X}, .device = {device_ref}, .num_devices = {num_devices}}} """))[:-1].format(populated=populated, device_ref=device_ref, num_devices=num_devices)) else: for name in self._enum_path[len(path)].Names(): value = self._GenerateRevisionMapRecursive( path + [name], device_ref_by_path, revision_key) parts.append(' [{name}] = {value},'.format( name=name.CName(), value=c_helpers.Indent(value)[2:])) parts.append('}') return '\n'.join(parts)
def _GenerateDeviceReference(self, type_name, path, num_devices, device_text, device_ref_by_text): """Helper function for GenerateMap and GenerateMapByAddress. Args: type_name: Specify 'Monitor' or 'MonitorDevice'. path: A list of pack2 enum names describing the configuration type. num_devices: Total number of devices in list. device_text: Source code initialization of device corresponding to path. device_ref_by_text: A dict mapping the source code initialization to variable reference. This function updates this map. Returns: A tuple containing the device reference and a list of source code outputs. """ # Parts in output. device_parts = [] # If device_text exists in device_ref_by_text, do not duplicate. if device_text in device_ref_by_text: device_ref = device_ref_by_text[device_text] elif num_devices > 0: device_ref = 'kDevice{}'.format(self._PathToString(path)) device_ref_by_text[device_text] = device_ref device_parts.append( textwrap.dedent("""\ static const {type_prefix}{type_name} {device_ref}[{num}] = {{ {text}}}; """).format(type_prefix=self._type_prefix, type_name=type_name, device_ref=device_ref, text=c_helpers.Indent(device_text), num=num_devices)) else: device_ref = 'NULL' device_ref_by_text[device_text] = device_ref return (device_ref, device_parts)
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 _GenerateSource(info_map, header_file): """Generate output source file as a string.""" parts = [ textwrap.dedent("""\ #include "{header_file}" #include <assert.h> #include <stdbool.h> #include <stddef.h> #include <stdint.h> """).format(header_file=header_file) ] includes = aio_message.GetHeaderFilesFromMessageInfoMap(info_map) includes += ['avionics/network/message_type.h'] parts += ['#include "%s"' % f for f in sorted(includes)] parts.append( '\nconst AioMessageInfo kAioMessageInfo[kNumMessageTypes] = {') for message in sorted(info_map.keys(), key=lambda m: m.name): info = info_map[message] if info: parts.append( c_helpers.Indent( textwrap.dedent("""\ [{enum_name}] = {{ .name = "{enum_name}", .short_name = "{short_name}", .pack_func = (PackAioMessageFunction){pack_func}, .unpack_func = (UnpackAioMessageFunction){unpack_func}, .pack_size = {pack_size}, .unpack_size = {unpack_size}}},""").format( enum_name=message.enum_name, short_name=message.name, pack_func=info.pack_func, pack_size=info.pack_size, unpack_func=info.unpack_func, unpack_size=info.unpack_size))) else: parts.append( c_helpers.Indent( textwrap.dedent("""\ [{enum_name}] = {{ .name = "{enum_name}", .short_name = "{short_name}", .pack_func = NULL, .unpack_func = NULL, .pack_size = -1, .unpack_size = -1}},""").format(enum_name=message.enum_name, short_name=message.name))) parts.append('};') parts.append( textwrap.dedent(""" size_t PackAioMessageData(MessageType type, const void *in, uint8_t *out) { if (type < kNumMessageTypes && kAioMessageInfo[type].pack_func != NULL) { return kAioMessageInfo[type].pack_func(in, 1, out); } assert(false); return 0; } size_t UnpackAioMessageData(MessageType type, const uint8_t *in, void *out) { if (type < kNumMessageTypes && kAioMessageInfo[type].unpack_func != NULL) { return kAioMessageInfo[type].unpack_func(in, 1, out); } assert(false); return 0; } """)) return '\n'.join(parts)