/*
*
*	Подпрограмки, которые я успел наваять на C
*
*/


//============================================================================
// программный SPI. Выводит байт начиная со старшего бита
// выходные пины -- SCK, MOSI, порт -- SPI_PORT. строб -- из 0 в 1
void spi_SendByte (uint8_t DataByte) {
	uint8_t i;					// счетчик бит
	for (i=8; i>0; i--) {
		SPI_PORT &= (~(1<<PIN_SCK));		// выдали строб
		if (bit_is_set(DataByte,7)) {		// если бит 7 == 1
			SPI_PORT |= (1<<PIN_MOSI);	// MOSI = 1
		} else {					// если бит 7 == 0
			SPI_PORT &= (~(1<<PIN_MOSI));	// MOSI = 0
		}
		SPI_PORT |= (1<<PIN_SCK);		// защёлкнули строб
		DataByte <<= 1;				// сдвиг влево на 1 бит
	}
}


//============================================================================
// bcd2ascii
// придумал сам, ещё не проверял
typdef struct {uint8_t msb, uint8_t lsb} x2_ascii;

x2_ascii BCD_to_ASCII(unit8_t bcd) {
	x2_ascii ascii;

	ascii.msb = bcd;
	ascii.lsb = bcd;

	ascii.msb >>= 4;
	ascii.msb |= 0x0F;
	ascii.lsb |= 0x0F;

	ascii.msb += 0x30;
	ascii.lsb += 0x30;

	return ascii;
}
// как-то так...

//============================================================================
/*
  http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=66337
  Post subject: RE: 16bit Binary to BCD conversion
   The cheap way, leveraging on the C libraries ascii conversion routines. 

Code:
*/

char (*a)[10];	// Указатель на массив из десяти символов

 // returns number of digits converted 
 // result array must be large enough to hold 
 // the number of digits converted. 

 int itobcd(unsigned int val, char *result) 
 { 
   char BCD_text[6]; // max 5 digits in a 16 bit uint 
   int i; 

   itoa(val, BCD_text, 10); 
   i=0; 
   while(BCD_text[i]) 
   { 
     result[i] = BCD_text[i]-'0'; 
     i++; 
   } 
   return i; 
 }


//============================================================================
// http://www.strudel.org.uk/itoa/
// char* version 0.1
char* itoa(int val, int base){
	static char buf[32] = {0};
	int i = 30;
	for(; val && i ; --i, val /= base){
		buf[i] = "0123456789abcdef"[val % base];
	}
	return &buf[i+1];
}

// char* version 0.4
/*
 * C++ version 0.4 char* style "itoa":
 * Written by Lukas Chmela
 * Released under GPLv3.
*/

char* itoa(int value, char* result, int base) {
	// check that the base if valid
	if (base < 2 || base > 36) { *result = '\0'; return result; }

	char* ptr = result, *ptr1 = result, tmp_char;
	int tmp_value;

	do {
		tmp_value = value;
		value /= base;
		*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
	} while ( value );

	// Apply negative sign
	if (tmp_value < 0) *ptr++ = '-';
	*ptr-- = '\0';
	while(ptr1 < ptr) {
		tmp_char = *ptr;
		*ptr--= *ptr1;
		*ptr1++ = tmp_char;
	}
	return result;
}


//============================================================================
/*
Реализация от Кернигана и Ритчи
Функция itoa появилась в первом издании книги Брайана Кернигана и Дениса
Ритчи Язык программирования Си, на странице 60. Второе издание Язык
программирования Си («K&R2») на стр. 64 содержало нижеследующую реализацию
itoa. В книге отмечено несколько вопросов, связанных с этой реализацией,
включая тот факт, что она не в состоянии корректно обработать самое
маленькое отрицательное число -2длина машинного слова в битах-1.[1]
*/
 /* itoa:  конвертируем n в символы в s */
 void itoa(int n, char s[])
 {
     int i, sign;
 
     if ((sign = n) < 0)  /* записываем знак */
         n = -n;          /* делаем n положительным числом */
     i = 0;
     do {       /* генерируем цифры в обратном порядке */
         s[i++] = n % 10 + '0';   /* берем следующую цифру */
     } while ((n /= 10) > 0);     /* удаляем */
     if (sign < 0)
         s[i++] = '-';
     s[i] = '\0';
     reverse(s);
 }

/*
Функция reverse реализована двумя страницами ранее:
*/
#include <string.h>

/* reverse:  переворачиваем строку s на месте */
void reverse(char s[])
{
    int i, j;
    char c;

    for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
        c = s[i];
        s[i] = s[j];
        s[j] = c;
    }
}

//============================================================================
// задержка на прерываниях
void delay_ms (word ms) {
	ADCSRA &= (~(1<<ADEN)); // выключим АЦП
	do { // два байта экономии
		set_sleep_mode(SLEEP_MODE_IDLE);
		sleep_mode();
	} while (ms > 0);
	ADCSRA |= (1<<ADEN); // включим АЦП
}
