// Some useful utilities for AVR
// This work is provided as-is without any warranty whatsoever
// Use it at your own risk
// Modify and redistribute at will, as long as this disclaimer remains
// (C) Brian Starkey, 2011

#include <avr/io.h>
#include <avr/pgmspace.h>

#include "avr_utils.h"

const char hexchars[] PROGMEM = "0123456789ABCDEF";
volatile char avru_flags;

void ctos(char * s, unsigned char i) {
	s[3] = '\0';
	s[0] = (i/100) | 0x30;
	if (s[0] == 0x30) s[0] = ' ';
	s[1] = (i/10)%10 | 0x30;
	if ((s[1] == 0x30) && (s[0] == ' ')) s[1] = ' ';
	s[2] = (i%10) | 0x30;
}

unsigned int atoi(char * string) {
	unsigned char i=0;
	unsigned int result = 0;
	for (i = 0; (string[i] >= '0') && (string[i] <= '9'); i++) {
		result *= 10;
		result += string[i] - '0';
	}
	return result;
}

unsigned char hextodec(char * hex) {
	unsigned char dec = 0;
	unsigned char i;
	avru_flags &= ~(AVRU_FLAGS_INVALID_NUMBER);
	for (i = 0; i < 2; i++) {
		unsigned char digit = hex[i];
		if ((digit >= 97) && (digit <= 102)) {
			digit -= 32;
		}
		dec <<= 4;
		if ((digit >= 0x41) && (digit <= 0x46)) {
			digit += 9;
		}
		else if ((digit < 0x30) || (digit > 0x39)) {
			avru_flags |= AVRU_FLAGS_INVALID_NUMBER;
			return 0;
		}
		dec |= (digit & 0x0F);
	}
	return dec;
}

void dectohex(unsigned char dec, char * buffer) {
	buffer[1] = (pgm_read_byte(&hexchars[dec & 0x0F]));
	dec >>= 4;
	buffer[0] = (pgm_read_byte(&hexchars[dec]));
}

unsigned char isalphanum(char check) {
	if ((check >= '0') && (check <= '9')) {
		return 1;
	}
	else if ((check >= 'a') && (check <= 'z')) {
		return 1;
	}
	else if ((check >= 'A') && (check <= 'Z')) {
		return 1;
	}
	return 0;
}

unsigned char alltoi(char * string) {
	unsigned char number;
	
	avru_flags &= ~(AVRU_FLAGS_INVALID_NUMBER);
	
	if ((string[0] >= '0') && (string[0] <= '9'))
	{
		if ((string[1] == 'x') || (string[1] == 'X'))
		{
			number = hextodec(string + 2);
		}
		else if ((string[1] >= '0') && (string[1] <= '9'))
		{
			number = (unsigned char)atoi(string);
		}
		else {
			number = string[0] - '0';
		}
		return number;
	}
	else
	{
		avru_flags |= AVRU_FLAGS_INVALID_NUMBER;
		return 0;
	}	
}
