function(from_hex HEX DEC)
	string(SUBSTRING "${HEX}" 2 -1 HEX)
	string(TOUPPER "${HEX}" HEX)
	set(_res 0)
	string(LENGTH "${HEX}" _strlen)

	while(_strlen GREATER 0)
		math(EXPR _res "${_res} * 16")
		string(SUBSTRING "${HEX}" 0 1 NIBBLE)
		string(SUBSTRING "${HEX}" 1 -1 HEX)
		if(NIBBLE STREQUAL "A")
			math(EXPR _res "${_res} + 10")
		elseif(NIBBLE STREQUAL "B")
			math(EXPR _res "${_res} + 11")
		elseif(NIBBLE STREQUAL "C")
			math(EXPR _res "${_res} + 12")
		elseif(NIBBLE STREQUAL "D")
			math(EXPR _res "${_res} + 13")
		elseif(NIBBLE STREQUAL "E")
			math(EXPR _res "${_res} + 14")
		elseif(NIBBLE STREQUAL "F")
			math(EXPR _res "${_res} + 15")
		else()
			math(EXPR _res "${_res} + ${NIBBLE}")
		endif()

		string(LENGTH "${HEX}" _strlen)
	endwhile()

	set(${DEC} ${_res} PARENT_SCOPE)
endfunction()

function(to_hex DEC HEX PREFIX)
	while(DEC GREATER 0)
		math(EXPR _val "${DEC} % 16")
		math(EXPR DEC "${DEC} / 16")
		if(_val EQUAL 10)
			set(_val "A")
		elseif(_val EQUAL 11)
			set(_val "B")
		elseif(_val EQUAL 12)
			set(_val "C")
		elseif(_val EQUAL 13)
			set(_val "D")
		elseif(_val EQUAL 14)
			set(_val "E")
		elseif(_val EQUAL 15)
			set(_val "F")
		endif()
		set(_res "${_val}${_res}")
	endwhile()
	set(${HEX} "${PREFIX}${_res}" PARENT_SCOPE)
endfunction()

function(to_hex_raw DEC HEX DIGITS PREFIX)
	set(counter 0)
	while(DEC GREATER 0)
		math(EXPR _val "${DEC} % 16")
		math(EXPR DEC "${DEC} / 16")
		if(_val EQUAL 10)
			set(_val "A")
		elseif(_val EQUAL 11)
			set(_val "B")
		elseif(_val EQUAL 12)
			set(_val "C")
		elseif(_val EQUAL 13)
			set(_val "D")
		elseif(_val EQUAL 14)
			set(_val "E")
		elseif(_val EQUAL 15)
			set(_val "F")
		endif()
		set(_res "${_val}${_res}")
		math(EXPR counter "${counter} + 1")
	endwhile()

	while(counter LESS DIGITS)
		set(_res "0${_res}")
		math(EXPR counter "${counter} + 1")
	endwhile()

	set(${HEX} "${PREFIX}${_res}" PARENT_SCOPE)
endfunction()

# Fill a particular value up to a number of digits (DIGITS) with a particular digit (FILL_DIGIT)
# It will add this digit as a prefix (for example to line values with preceding zeros)
# It will have an extra PREFIX that can be used as e.g. 0x to indicate it is a hex value.
function(fill VALUE OUTPUT DIGITS FILL_DIGIT PREFIX)
	string(LENGTH ${VALUE} counter)
	set(_res "${VALUE}")

	while(counter LESS DIGITS)
		set(_res "${FILL_DIGIT}${_res}")
		math(EXPR counter "${counter} + 1")
	endwhile()

	set(${OUTPUT} "${PREFIX}${_res}" PARENT_SCOPE)
endfunction()

# Reverse input at word boundaries DDCCBBAA becomes AABBCCDD
function(reverse_words VALUE OUTPUT SKIP DELIMITER)
	string(LENGTH ${VALUE} length)
	set(counter 0)
	set(_res "")
	message(STATUS "Length: ${length}")
	message(STATUS "Counter: ${counter}")
	while(counter LESS length)
		string(SUBSTRING "${VALUE}" ${counter} 2 WORD)
		message(STATUS "Word: ${WORD}")
		if (counter LESS SKIP)
			# do nothing
		elseif (counter EQUAL SKIP)
			set(_res "${WORD}${_res}")
		else()
			set(_res "${WORD}${DELIMITER}${_res}")
		endif()
		math(EXPR counter "${counter} + 2")
	endwhile()

	set(${OUTPUT} "${_res}" PARENT_SCOPE)
endfunction()

function(words VALUE OUTPUT SKIP DELIMITER)
	string(LENGTH ${VALUE} length)
	set(counter 0)
	set(_res "")
	#message(STATUS "Length: ${length}")
	#message(STATUS "Counter: ${counter}")
	while(counter LESS length)
		string(SUBSTRING "${VALUE}" ${counter} 2 WORD)
		if (counter LESS SKIP)
			# do nothing
		elseif (counter EQUAL SKIP)
			set(_res "${_res}${WORD}")
		else()
			set(_res "${_res}${DELIMITER}${WORD}")
		endif()
		math(EXPR counter "${counter} + 2")
	endwhile()

	set(${OUTPUT} "${_res}" PARENT_SCOPE)
endfunction()

# For new enough CMake builds
function(bitwise_or_hex VALUE MASK OUTPUT)
	math(EXPR _res "0x${VALUE} | ${MASK}" OUTPUT_FORMAT HEXADECIMAL)
	set(${OUTPUT} "${_res}" PARENT_SCOPE)
endfunction()

function(bitwise_or VALUE MASK OUTPUT)
	math(EXPR _res "${VALUE} | ${MASK}")
	set(${OUTPUT} "${_res}" PARENT_SCOPE)
endfunction()
