<commit_before># -*- coding: utf-8 -*-
# 
# Copyright (c) 2013, Roboterclub Aachen e.V.
# All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 
#  * Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#  * Neither the name of the Roboterclub Aachen e.V. nor the
#    names of its contributors may be used to endorse or promote products
#    derived from this software without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY ROBOTERCLUB AACHEN E.V. ''AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL ROBOTERCLUB AACHEN E.V. BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# -----------------------------------------------------------------------------

import re, os, sys
import xml.etree.ElementTree as et
import xml.parsers.expat
from string import Template
from parser_exception import ParserException
from device_element import DeviceElementBase, DeviceString

# add python module logger to path
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'logger'))
from logger import Logger

class DeviceFile:
	""" DeviceFile
	Represents a device target for xpcc.
	This can be a microcontroller, a pc or a doxygen "fake" target.
	"""

	PROPERTY_TAGS = ['flash', 'ram', 'eeprom', 'pin-count', 'define', 'header', 'linkerscript']

	def __init__(self, xml_file, logger=None):
		node = self._openDeviceXML(xml_file)

		if logger == None:
			self.log = Logger()
		else:
			self.log = logger

		self.platform = node.get('platform')
		self.family = node.get('family')
		self.names = node.get('name').split('|')

		self.properties = []
		self.drivers = []

		for c in node:
			if c.tag in self.PROPERTY_TAGS:
				self.properties.append(Property(self, c))
			elif c.tag in ['driver']:
				self.drivers.append(Driver(self, c))
			else:
				raise ParserException("Parse Error: unknown tag (%s)" % (c.tag))
		self._checkDeviceFileData(xml_file)

	def _openDeviceXML(self, filename):
		try:
			# parse the xml-file
			xmltree = et.parse(filename).getroot()
		except OSError as e:
			raise ParserException(e)
		except (xml.parsers.expat.ExpatError, xml.etree.ElementTree.ParseError) as e:
			raise ParserException("while parsing xml-file '%s': %s" % (filename, e))
		"""
		TODO: Validate!!
				try:
					import lxml.etree		# for validating
			
					# validate against the embedded DTD file
					try:
						parser = lxml.etree.XMLParser(dtd_validation=True)
						dummy = lxml.etree.parse(filename, parser)
					except lxml.etree.XMLSyntaxError as e:
						raise ParserException("Validation error in '%s': %s" % (filename, e))
					else:
						logging.debug("Validation OK!")
				except ImportError as e:
					logging.warning("Warning: couldn't load 'lxml' module. No validation done!")
		"""
		# since we have totally "validated" our xml file (see above) we can
		# expect that all required elements exist...
		return xmltree[0]

	def _checkDeviceFileData(self, xml_file):
		"""
		This checks if there are any problems with the device file.
		It also considers the different requirements of the various platforms.
		Warnings/Errors are logged when a problem is discovered. An information
		is logged when there is something that probably could be improved.
		This method won't throw any errors because any error that prevents the
		device to be built will be discovered later. It is intended to notify
		users if device files aren't completely correct instead.
		"""
		# Print some Information
		self.log.info("Using Xml Device File '%s'" % os.path.basename(xml_file))
		self.log.info("Found %s Properties:" % len(self.properties))
		# Check Properties
		prop_count = {}
		for prop in self.properties:
			if prop.type in prop_count:
				prop_count[prop.type] += 1
			else:
				prop_count[prop.type] = 1
		self.log.info("Found %s Drivers" % len(self.drivers))
		# Checks for all Platforms

		# Checks for STM32 Platform
		if self.platform == 'stm32':
			families = ['f0', 'f1', 'f2', 'f3', 'f4']
			if self.family not in families:
				self.log.error("Unknown family '%s' for platform %s."
				" Valid families for this platform are: %s" %
				(self.family, self.platform, families))
		elif self.platform == 'avr':
			pass
		else:
			self.log.error("Unknown platform '%s'" % self.platform)



##-------------  Methods used by the SCons Platform Tools ---------------------
	def getProperties(self, device_string):
		"""
		Returns a dictionary containing:
		'flash', 'ram', 'pin-count' and 'defines'
		that are specific to the device_string.

		This is used by the Scons Platform Tools. Think before editing.
		TODO: defines, flash and ram may depend on pin-count....<commit_msg>Tools: Device: Check for correct family.<commit_after># -*- coding: utf-8 -*-
# 
# Copyright (c) 2013, Roboterclub Aachen e.V.
# All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 
#  * Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#  * Neither the name of the Roboterclub Aachen e.V. nor the
#    names of its contributors may be used to endorse or promote products
#    derived from this software without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY <NAME>.V. ''AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL ROBOTERCLUB AACHEN E.V. BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# -----------------------------------------------------------------------------

import re, os, sys
import xml.etree.ElementTree as et
import xml.parsers.expat
from string import Template
from parser_exception import ParserException
from device_element import DeviceElementBase, DeviceString

# add python module logger to path
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'logger'))
from logger import Logger

class DeviceFile:
	""" DeviceFile
	Represents a device target for xpcc.
	This can be a microcontroller, a pc or a doxygen "fake" target.
	"""

	PROPERTY_TAGS = ['flash', 'ram', 'eeprom', 'pin-count', 'define', 'header', 'linkerscript']

	def __init__(self, xml_file, logger=None):
		node = self._openDeviceXML(xml_file)

		if logger == None:
			self.log = Logger()
		else:
			self.log = logger

		self.platform = node.get('platform')
		self.family = node.get('family')
		self.names = node.get('name').split('|')

		self.properties = []
		self.drivers = []

		for c in node:
			if c.tag in self.PROPERTY_TAGS:
				self.properties.append(Property(self, c))
			elif c.tag in ['driver']:
				self.drivers.append(Driver(self, c))
			else:
				raise ParserException("Parse Error: unknown tag (%s)" % (c.tag))
		self._checkDeviceFileData(xml_file)

	def _openDeviceXML(self, filename):
		try:
			# parse the xml-file
			xmltree = et.parse(filename).getroot()
		except OSError as e:
			raise ParserException(e)
		except (xml.parsers.expat.ExpatError, xml.etree.ElementTree.ParseError) as e:
			raise ParserException("while parsing xml-file '%s': %s" % (filename, e))
		"""
		TODO: Validate!!
				try:
					import lxml.etree		# for validating
			
					# validate against the embedded DTD file
					try:
						parser = lxml.etree.XMLParser(dtd_validation=True)
						dummy = lxml.etree.parse(filename, parser)
					except lxml.etree.XMLSyntaxError as e:
						raise ParserException("Validation error in '%s': %s" % (filename, e))
					else:
						logging.debug("Validation OK!")
				except ImportError as e:
					logging.warning("Warning: couldn't load 'lxml' module. No validation done!")
		"""
		# since we have totally "validated" our xml file (see above) we can
		# expect that all required elements exist...
		return xmltree[0]

	def _checkDeviceFileData(self, xml_file):
		"""
		This checks if there are any problems with the device file.
		It also considers the different requirements of the various platforms.
		Warnings/Errors are logged when a problem is discovered. An information
		is logged when there is something that probably could be improved.
		This method won't throw any errors because any error that prevents the
		device to be built will be discovered later. It is intended to notify
		users if device files aren't completely correct instead.
		"""
		# Print some Information
		self.log.info("Using Xml Device File '%s'" % os.path.basename(xml_file))
		self.log.info("Found %s Properties:" % len(self.properties))
		# Check Properties
		prop_count = {}
		for prop in self.properties:
			if prop.type in prop_count:
				prop_count[prop.type] += 1
			else:
				prop_count[prop.type] = 1
		self.log.info("Found %s Drivers" % len(self.drivers))
		# Checks for all Platforms

		# Checks for STM32 Platform
		if self.platform == 'stm32':
			families = ['f0', 'f1', 'f2', 'f3', 'f4']
			if self.family not in families:
				self.log.error("Unknown family '%s' for platform %s."
				" Valid families for this platform are: %s" %
				(self.family, self.platform, families))
		elif self.platform == 'avr':
			families = ['at90','attiny', 'atmega', 'atxmega']
			if self.family not in families:
				self.log.error("Unknown family '%s' for platform %s."
				" Valid families for this platform are: %s" %
				(self.family, self.platform, families))
			pass
		else:
			self.log.error("Unknown platform '%s'" % self.platform)



##-------------  Methods used by the SCons Platform Tools ---------------------
	def getProperties(self, device_string):
		"""
		Returns a dictionary containing:
		'flash', 'ram', 'pin-count' and 'defines'
		that are specific to the device_string.

		This is used by the Scons Platform Tools. Think before editing.
		TODO: defines, flash and ram may depend on pin-count....
{'fraction_non_alphanumeric': 0.11718818476641248, 'fraction_numerical': 0.003155403628714173, 'mean_word_length': 3.5403899721448466, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 38}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6860644', 'n_tokens_mistral': 3721, 'n_tokens_neox': 3251, 'n_words': 1287}