示例#1
0
/// Just like txAlfaBravoCharlie, but adds digits from
/// the stack to expose the entire alphabet.
void txAlphaNNN(MorseToken) {
  uint8_t n(0);
  uint8_t k(symbolStackSize());
  if (0 < k) {
    n += s(0).m2i();
    popSymbolStack(MorseToken());
  }
  if (1 < k) {
    n += 10 * s(1).m2i();
    popSymbolStack(MorseToken());
  }
  if (0 <= n && n <= ('Z' - 'A')) {
    char letterName[1 + sizeof "NOVEMBER"];
    const char* p(alphaBravoCharlie);
    size_t i(0);
    while (*p) {
      if (*p == ' ') {
	if (n) {
	  --n;
	} else {
	  break;
	}
      } else if (!n) {
	letterName[i++] = *p;
      }
      ++p;
    }
    txString(letterName);
  } else {
    txError();
  }
}
示例#2
0
void gradeNext(MorseToken) {
   if (1 < symbolStackSize()) {
      if (s(1) == s(0)) {
         txString("Y");
         popSymbolStack(MorseToken());
         popSymbolStack(MorseToken());
      } else {
         txString("N");
         popSymbolStack(MorseToken());
         txSymbolStackTop(MorseToken());
         popSymbolStack(MorseToken());
      }
   } else {
      txError();
   }
}
示例#3
0
void txAlfaBravoCharlie(MorseToken code) {
   //  uint8_t n(m2a(code) - 'A');
   uint8_t n(0);
   if (1 < symbolStackSize()) {
      n = 10 * s(1).m2i() + s(0).m2i();
      popN(2);
   } else if (symbolStackSize()) {
      n = m2i(s(0));
      popN(1);
   }
   if (0 <= n && n <= ('Z' - 'A')) {
      char letterName[1 + sizeof "NOVEMBER"];
      const char* p(alphaBravoCharlie);
      size_t i(0);
      while (*p) {
         if (*p == ' ') {
            if (n) {
               --n;
            } else {
               break;
            }
         } else if (!n) {
            letterName[i++] = *p;
         }
         ++p;
      }
      letterName[i] = '\000';
      txString(letterName);
   } else {
      txError();
      Serial.println("txAlfaBravoCharlie: Range error.");
   }
}
示例#4
0
/// Play the A.B.C's with each single syllable letter replaced by the
/// corresponding Morse code. W is transmitted once for each syllable.
/// After Z, the remainder of the song is played as simple tones.
void txAlphabetSong(MorseToken) {
  uint32_t saveHz(getTxHz());
  int saveDitMicros(getDitMicros());
  const char* letters("ABCDEFGHIJKLMNOPQRSTUVWWWXY Z ");
  const char*
    notes("C42C42G42G42" "A52A52G44" "F42F42E42E42" "D41D41D41D41C44"
	  "G42G42F44"    "E42E42D44" "G41G41G42F44" "E42E42D44"
	  "C42C42G42G42" "A52A52G44" "F42F42E42E42" "D42D42C44");
  char* l(const_cast<char*>(letters));
  char* p(const_cast<char*>(notes));
  while (*p) {
    size_t steps[] = { 0, 2, 3, 5, 7, 8, 10 };
    size_t note(steps[p[0] - 'A'] + 12 * (p[1]-'0'));
    size_t frequency(noteHz[note] + 0.5);
    size_t duration(saveDitMicros * (p[2] - '0') * 2 / 3);
    char buffer[] = { '\0', ' ', '\0' };
    buffer[0] = l[0];
    if (l[1]) {
      setTxHz(frequency);
      setDitMicros(duration);
      txString(buffer);
      delayMicroseconds((14 * saveDitMicros + 1) -
			(saveDitMicros * durationDits(l[0])));
      ++l;
    } else {
      // This part goes much faster, but it doesn't convey much
      // information.
      playTone(frequency, duration);
    }
    p += 3;
  }
  setTxHz(saveHz);
  setDitMicros(saveDitMicros);
}
示例#5
0
/// Prompt with a random letter of the alphabet. The user enters the
/// letter then enters I to get graded.
void askNext(MorseToken) {
   uint8_t a(random(26));
   char buffer[3] = { char(a + 'A'), 0 };
   txString(buffer);
   uint8_t b((a + 1) % 26);
   pushSymbolStack(MorseToken(b + 'A', MorseToken::Char));
   assignAction(MorseToken('I', MorseToken::Char), gradeNext);
   saveActions();
   for (size_t i('A'); i <= 'Z' ; ++i) {
      assignAction(MorseToken(i, MorseToken::Char), push1RestoreAll);
   }
}
示例#6
0
/// Present a simple challenge consisting of two random digits to 
/// add. The user tries to enter the last digit of their sum.
void askSum(MorseToken) {
   uint8_t a(getDigitByWeight());
   uint8_t b(getDigitByWeight());
   char buffer[3] = { char(a + '0'), char(b + '0'), 0 };
   txString(buffer);
   pushSymbolStack(MorseToken(buffer[0], MorseToken::Char));
   pushSymbolStack(MorseToken(buffer[1], MorseToken::Char));
   saveActions();
   for (size_t i('0'); i <= '9' ; ++i) {
      assignAction(MorseToken(i, MorseToken::Char), gradeRestore);
   }
}
示例#7
0
/// The top three entries on the stack are two digits to add and their
/// proported sum mod 10. Transmit Y/N to indicate whether or not the
/// sum is correct. If the sum is not correct, transmit the correct
/// sum. Update the weights to bias future random number selection.
void gradeSum(MorseToken) {
  if (2 < symbolStackSize()) {
    uint8_t s1(s(1).m2i());
    uint8_t s2(s(2).m2i());
    uint8_t s0(s(0).toChar());
    uint8_t sum((s1 + s2) % 10);
    Serial.print(s2);
    Serial.print(" ");
    Serial.print(s1);
    Serial.print(" ");
    Serial.print(s0);
    Serial.print(" sum: ");
    Serial.println(sum);
    bool correct(s(0).m2i() == sum);
    if (correct) {
      txString("Y");
      // Decrease the error counts associated with the digits the user
      // just added incorrectly, taking care not to underflow.
      uint8_t d1(!!digitErr[s1]);
      uint8_t d2(!!digitErr[s2]);
      digitErr[s1] -= d1; 
      digitErr[s2] -= d2;
      digitErrCount -= (d1 + d2);
      Serial.print("Decrementing ");
      Serial.print(s1);
      Serial.print(". New weight is: ");
      Serial.println(digitErr[s1]);
      Serial.print("Decrementing ");
      Serial.print(s2);
      Serial.print(". New weight is: ");
      Serial.println(digitErr[s2]);
    } else {
      //            012345678901
      char buffer[] = "N  a + b = c";
      buffer[3] = s2 + '0';
      buffer[7] = s1 + '0';
      buffer[11] = sum + '0';
      txString(buffer);
      // Increase the error counts associated with the digits the user
      // just added incorrectly, taking care not to overflow.
      uint8_t d1(3 * (digitErr[s1] - 3 < 255));
      uint8_t d2(3 * (digitErr[s2] - 3 < 255));
      digitErr[s1] += d1;
      digitErr[s2] += d2;
      digitErrCount += d1 + d2;
      Serial.print("Incrementing ");
      Serial.print(s1);
      Serial.print(". New weight is: ");
      Serial.println(digitErr[s1]);
      Serial.print("Incrementing ");
      Serial.print(s2);
      Serial.print(". New weight is: ");
      Serial.println(digitErr[s2]);
    }
    // If the user plays long enough without a reset to saturate two
    // of the digits chosen at random, divide all the error counts
    // by 2.
    if (digitErr[s1] == 255 && digitErr[s2] == 255) {
      for (uint8_t i(0); i < 10; ++i) {
	digitErr[i] <<= 1;
      }
      digitErrCount <<= 1;
      Serial.println("Halving all weights.");
    }
    Serial.print("Digit error count is: ");
    Serial.println(digitErrCount);
    popN(3);
  } else {
    txError();
  }
}
示例#8
0
/// Play one of 10 sound effects based on the digit on the stack.
void playSoundEffect(MorseToken code) {
  pwmFrequency(noteHz[48]+0.5);
  pwmWrite(getDuty());
  delayMicroseconds(getDitMicros());
  pwmWrite(0);
  if (symbolStackSize()) {
    uint8_t n(s(0).m2i());
    elapsedMicros t;
    size_t steps[] = { 0, 2, 3, 5, 7, 8, 10 };
    switch (n) {
    case 0:
      t = 0;
      // Low pulsing static rumble
      while (t < 60 * getDitMicrosDefault()) {
	for (int i(1); i < 25; ++i) {
	  dWrite(HIGH);
	  delayMicroseconds((1 + random(i)) * 1136);
	  dWrite(LOW);
	  delayMicroseconds((1 + random(i)) * 1136);
	}
      }
      break;
    case 1:
      shufflingCash(120 * getDitMicrosDefault());
      break;
    case 2:
      t = 0;
      // Descending beats
      while (t < 120 * getDitMicrosDefault()) {
	for (int i(1); i < 75; ++i) {
	  dWrite(HIGH);
	  delayMicroseconds(i * 1136/12);
	  dWrite(LOW);
	  delayMicroseconds(i * 1136/12);
	}
      }
      break;
    case 3:
      t = 0;
      // Buzzer
      while (t < 60 * getDitMicrosDefault()) {
	playTone(noteHz[36], getDitMicrosDefault()/30);
	playTone(noteHz[48], getDitMicrosDefault()/30);
	playTone(noteHz[52], getDitMicrosDefault()/60);
	playTone(noteHz[57], getDitMicrosDefault()/60);
      }
      break;
    case 4:
      t = 0;
      // Humm, kinda like a machine hum.
      while (t < 60 * getDitMicrosDefault()) {
	for (int i(0); i < 49; ++i) {
	  playTone(noteHz[i], getDitMicrosDefault()/10);
	}
      }
      break;
    case 5:
      t = 0;
      // ascending and repeating 
      while (t < 60 * getDitMicrosDefault()) {
	for (int i(0); i < 49; ++i) {
	  playTone(noteHz[i], getDitMicrosDefault()/2);
	}
      }
      break;
    case 6:
      t = 0;
      // ascending more quickly
      while (t < 60 * getDitMicrosDefault()) {
	for (int i(0); i < 49; ++i) {
	  playTone(noteHz[random(1,96)], getDitMicrosDefault()/10);
	}
      }
      break;
    case 7:
      t = 0;
      // ?
      while (t < 60 * getDitMicrosDefault()) {
	for (int i(0); i < 7; ++i) {
	  playTone(noteHz[(24 + steps[i % 7]) % 97], getDitMicrosDefault());
	}
      }
      break;
    case 8:
      t = 0;
      // Almost white noise, like water from a tap
      while (t < 60 * getDitMicrosDefault()) {
	dWrite(HIGH);
	delayMicroseconds(random(100,1000));
	dWrite(LOW);
	delayMicroseconds(random(100,1000));
      }
      break;
    case 9:
      t = 0;
      // Almost white noise, like water from a tap
      while (t < 60 * getDitMicrosDefault()) {
	dWrite(HIGH);
	delayMicroseconds(random(10,8000));
	dWrite(LOW);
	delayMicroseconds(random(10,8000));
      }
      t = 0;
      // Sort of like a pinball machine
      { int i(2);
	while (t < 60 * getDitMicrosDefault()) {
	  for (int k(0); k < 10; ++k) {
	    dWrite(HIGH);
	    delayMicroseconds(i);
	    dWrite(LOW);
	    delayMicroseconds(i);
	  }
	  i <<= 2;
	  if (4000 < i) { i = 2; }
	}
      }
    }
    txString("K");
  } else {
    txError();
  }
}
示例#9
0
/*
  * fct_SDCard.c
 *
 *  Created on: 21 juin 2016
 *      Author: formateur
 */

#include <avr/io.h>
#include <util/delay.h>

#include "../lib/usart.h"
#include "../lib/fct_spi.h"
#include "../lib/fct_SDCard.h"



//******************************************************************
//Function	: to initialize the SD/SDHC card in SPI mode
//Arguments	: none
//return	: unsigned char; will be 0 if no error,
// 			  otherwise the response byte will be sent
//******************************************************************
unsigned char SD_init(void)
{
	unsigned char response, SD_version;
	unsigned int retry=0 ;
	int i=0;

	//Spi init
	spi_init();																/**send init on spi peripheral**/

	for(i=0;i<10;i++){
		SD_CS_ASSERT;														/**set chip select*/
		do
		{
		   response = SD_sendCommand(GO_IDLE_STATE, 0); 					/**send software reset */
		   retry++;
		   if(retry>0x20){
			   //
			  USART0_print("\rpas de carte\n");
			   //
			   return 1;  													/**time out, card not detected*/
		   }


		} while(response != 0x01);											/**response= 0x01 : card in idle state and no error*/

		SD_CS_DEASSERT;
		SPI_transmit (0xff);												/**1st byte transmission  */
		SPI_transmit (0xff);												/**2nd byte transmission */

		retry = 0;															/**reset retries counter*/

		SD_version = 2; //default set to SD compliance with ver2.x;
						//this may change after checking the next command
		do
		{
		response = SD_sendCommand(SEND_IF_COND,0x000001AA); 				/**check power supply status,for SDHC card*/
		retry++;
		if(retry>0xfe)
		   {
			  SD_version = 1;
			  cardType = 1;
			  break;
		   } //time out

		}while(response != 0x01);

		retry = 0;

		do
		{
		response = SD_sendCommand(APP_CMD,0); //CMD55, must be sent before sending any ACMD command
		response = SD_sendCommand(SD_SEND_OP_COND,0x40000000); //ACMD41

		retry++;
		if(retry>0xfe)
		   {
			  USART0_print("\rinitialisation a échoué\n");
			  return 2;  //time out, card initialization failed
		   }

		}while(response != 0x00);


		retry = 0;
		SDHC_flag = 0;

		if (SD_version == 2)
		{
		   do
		   {
			 response = SD_sendCommand(READ_OCR,0);
			 retry++;
			 if(retry>0xfe)
			 {
			   cardType = 0;
			   break;
			 } //time out

		   }while(response != 0x00);

		   if(SDHC_flag == 1) cardType = 2;
		   else cardType = 3;
		}

		//SD_sendCommand(CRC_ON_OFF, OFF); //disable CRC; deafault - CRC disabled in SPI mode
		//SD_sendCommand(SET_BLOCK_LEN, 512); //set block size to 512; default size is 512

		//
		switch (cardType)													/** switch for card type (to check communication with the card)*/
		{
		case 1 :  USART0_print("\rver1.x\n");break;
		case 2 :  USART0_print("\rSDHC\n");break;
		case 3 :  USART0_print("\rver2.x\n");break;
		default : USART0_print("runknown Sd card\n");
		}
		//

	return 0;break;															/**successful return*/
	}
	_delay_ms(1);															/**give some time to end the init*/
	return 0;
}


//******************************************************************
//Function	: to send a command to SD card
//Arguments	: unsigned char (8-bit command value)
// 			  & unsigned long (32-bit command argument)
//return	: unsigned char; response byte
//******************************************************************

unsigned char SD_sendCommand(unsigned char cmd, unsigned long arg)
{
	unsigned char response, retry=0, status;

	//SD card accepts byte address while SDHC accepts block address in multiples of 512
	//so, if it's SD card we need to convert block address into corresponding byte address by
	//multipying it with 512. which is equivalent to shifting it left 9 times
	//following 'if' loop does that

		if(SDHC_flag == 0)
			if(cmd == READ_SINGLE_BLOCK     ||
			   cmd == READ_MULTIPLE_BLOCKS  ||
			   cmd == WRITE_SINGLE_BLOCK    ||
			   cmd == WRITE_MULTIPLE_BLOCKS ||
			   cmd == ERASE_BLOCK_START_ADDR||
			   cmd == ERASE_BLOCK_END_ADDR )
			   {
				 	 arg = arg << 9;
			   }

		SD_CS_ASSERT;

		SPI_transmit(cmd | 0x40); //send command, first two bits always '01'
		SPI_transmit(arg>>24);
		SPI_transmit(arg>>16);
		SPI_transmit(arg>>8);
		SPI_transmit(arg);

		if(cmd == SEND_IF_COND)	 //it is compulsory to send correct CRC for CMD8 (CRC=0x87) & CMD0 (CRC=0x95)
			SPI_transmit(0x87);    //for remaining commands, CRC is ignored in SPI mode
		else
			SPI_transmit(0x95);

		while((response = SPI_receive()) == 0xff) //wait response
			if(retry++ > 0xfe) break; //time out error

		if(response == 0x00 && cmd == 58)  //checking response of CMD58
		{
			  status = SPI_receive() & 0x40;     //first byte of the OCR register (bit 31:24)
			  if(status == 0x40) SDHC_flag = 1;  //we need it to verify SDHC card
			  else SDHC_flag = 0;

			  SPI_receive(); //remaining 3 bytes of the OCR register are ignored here
			  SPI_receive(); //one can use these bytes to check power supply limits of SD
			  SPI_receive();
		}

		SPI_receive(); //extra 8 CLK
		SD_CS_DEASSERT;


	return response; //return state
}

//*****************************************************************
//Function	: to erase specified no. of blocks of SD card
//Arguments	: none
//return	: unsigned char; will be 0 if no error,
// 			  otherwise the response byte will be sent
//*****************************************************************

unsigned char SD_erase (unsigned long startBlock, unsigned long totalBlocks)
{
	unsigned char response;

		response = SD_sendCommand(ERASE_BLOCK_START_ADDR, startBlock); 						/**send address of starting block*/
		if(response != 0x00) 																/**check the SD status: 0x00 - OK (No flags set)*/
		  return response;

		response = SD_sendCommand(ERASE_BLOCK_END_ADDR,(startBlock + totalBlocks - 1));		/**send adress of end block*/
		if(response != 0x00)																/**check the SD status: 0x00 - OK (No flags set)*/
		  return response;

		response = SD_sendCommand(ERASE_SELECTED_BLOCKS, 0); 								/**erase all selected blocks*/
		if(response != 0x00)																/**check SD status: 0x00 - OK (No flags set)*/
		  return response;

	return 0; //normal return
}

//******************************************************************
//Function	: to read a single block from SD card
//Arguments	: none
//return	: unsigned char; will be 0 if no error,
// 			  otherwise the response byte will be sent
//******************************************************************

unsigned char SD_readSingleBlock(unsigned long startBlock)
{
	unsigned char response;
	unsigned int i, retry=0;

		 response = SD_sendCommand(READ_SINGLE_BLOCK, startBlock); 							/**read a Block command*/

		 if(response != 0x00) return response; 												/**check if SD status: 0x00 - OK (no flag activated)*/

		SD_CS_ASSERT;

		retry = 0;
		while(SPI_receive() != 0xfe) 														/**wait for start block to get the 0xfe value*/
		  if(retry++ > 0xfffe){
			  	 	 SD_CS_DEASSERT;
			  	 	 return 1;  } 															/**function output  time-out*/

		for(i=0; i<512; i++) 																/**read every 512 bytes*/
			buffer[i] = SPI_receive();


		SPI_receive(); 																		/**let 8 clock pulses*/
		SD_CS_DEASSERT;

	return 0;
}

//******************************************************************
//Function	: to write to a single block of SD card
//return	: unsigned char; will be 0 if no error,
// 			  otherwise the response byte will be sent
//******************************************************************

unsigned char SD_writeSingleBlock(unsigned long startBlock)
{
	unsigned char response;
	unsigned int i, retry=0;

		 response = SD_sendCommand(WRITE_SINGLE_BLOCK, startBlock); 						/** block's writing command*/

		 if(response != 0x00) return response; 												/**check if SD status: 0x00 - OK (no flag activated)*/

		SD_CS_ASSERT;

		SPI_transmit(0xfe);     															/**send the 0xfe block (page 197 datasheet SD)*/

		for(i=0; i<512; i++)    															/**send the 512 bytes data*/
			SPI_transmit(buffer[i]);

		SPI_transmit(0xff);     //transmit dummy CRC (16-bit), CRC is ignored here
		SPI_transmit(0xff);

		response = SPI_receive();

		if( (response & 0x1f) != 0x05)														 /**response= 0xXXX0AAA1 ; if: {	AAA='010' - data accepted
		                              						 	 																AAA='101'-data rejected due to CRC error
																																AAA='110'-data rejected due to write error
																															}*/
		{
			SD_CS_DEASSERT;
			return response;
		}

		while(!SPI_receive()) 																/**wait for SD card to complete the writing and go to get idle state*/
			if(retry++ > 0xfffe){SD_CS_DEASSERT; return 1;}									/**function output time-out*/

		SD_CS_DEASSERT;
		SPI_transmit(0xff);   																/**allow a 8 clock cycles delay before CS line reaffirming*/
		SD_CS_ASSERT;         																/**CS line reaffirming to check if the card is still busy*/

		while(!SPI_receive()) 																/**wait for SD card to complete the writing and go to get idle state*/
			if(retry++ > 0xfffe){
				SD_CS_DEASSERT; return 1;
			}

		SD_CS_DEASSERT;

	return 0;
}



#ifndef FAT_TESTING_ONLY

//***************************************************************************/
//Function	: to read multiple blocks from SD card & send every block to UART
//Arguments	: none
//return	: unsigned char; will be 0 if no error,
// 			  otherwise the response byte will be sent
//****************************************************************************/
unsigned char SD_readMultipleBlock (unsigned long startBlock, unsigned long totalBlocks)
{
unsigned char response;
unsigned int i, retry=0;

retry = 0;

response = SD_sendCommand(READ_MULTIPLE_BLOCKS, startBlock); //write a Block command

if(response != 0x00) return response; //check for SD status: 0x00 - OK (No flags set)

SD_CS_ASSERT;

while( totalBlocks )
{
  retry = 0;
  while(SPI_receive() != 0xfe) //wait for start block token 0xfe (0x11111110)
  if(retry++ > 0xfffe){SD_CS_DEASSERT; return 1;} //return if time-out

  for(i=0; i<512; i++) //read 512 bytes
    buffer[i] = SPI_receive();

  SPI_receive(); //receive incoming CRC (16-bit), CRC is ignored here
  SPI_receive();

  SPI_receive(); //extra 8 cycles
  TX_NEWLINE;
  transmitString_F(PSTR(" --------- "));
  TX_NEWLINE;

  for(i=0; i<512; i++) //send the block to UART
  {
    if(buffer[i] == '~') break;
    transmitByte ( buffer[i] );
  }

  TX_NEWLINE;
  transmitString_F(PSTR(" --------- "));
  TX_NEWLINE;
  totalBlocks--;
}

SD_sendCommand(STOP_TRANSMISSION, 0); //command to stop transmission
SD_CS_DEASSERT;
SPI_receive(); //extra 8 clock pulses

return 0;
}

//***************************************************************************/
//Function: to receive data from UART and write to multiple blocks of SD card
//Arguments: none
//return: unsigned char; will be 0 if no error,
// otherwise the response byte will be sent
//****************************************************************************/
unsigned char SD_writeMultipleBlock(unsigned long startBlock, unsigned long totalBlocks)
{
unsigned char response, data;
unsigned int i, retry=0;
unsigned long blockCounter=0, size;

response = SD_sendCommand(WRITE_MULTIPLE_BLOCKS, startBlock); //write a Block command

if(response != 0x00) return response; //check for SD status: 0x00 - OK (No flags set)

SD_CS_ASSERT;

TX_NEWLINE;
transmitString_F(PSTR(" Enter text (End with ~): "));
TX_NEWLINE;

while( blockCounter < totalBlocks )
{//e. Cette librairie est dépendante de la librairie SPI. Voici le code à m
   i=0;
   do
   {
     data = receiveByte();
     if(data == 0x08)	//'Back Space' key pressed
	 {
	   if(i != 0)
	   {
	     transmitByte(data);
	     transmitByte(' ');
	     transmitByte(data);
	     i--;
		 size--;
	   }
	   continue;
	 }
     transmitByte(data);
     buffer[i++] = data;
     if(data == 0x0d)
     {
        transmitByte(0x0a);
        buffer[i++] = 0x0a;
     }
	 if(i == 512) break;
   }while (data != '~');

   TX_NEWLINE;
   transmitString_F(PSTR(" ---- "));
   TX_NEWLINE;

   SPI_transmit(0xfc); //Send start block token 0xfc (0x11111100)

   for(i=0; i<512; i++) //send 512 bytes data
     SPI_transmit( buffer[i] );

   SPI_transmit(0xff); //transmit dummy CRC (16-bit), CRC is ignored here
   SPI_transmit(0xff);

   response = SPI_receive();
   if( (response & 0x1f) != 0x05) //response= 0xXXX0AAA1 ; AAA='010' - data accepted
   {                              //AAA='101'-data rejected due to CRC error
      SD_CS_DEASSERT;             //AAA='110'-data rejected due to write error
      return response;
   }

   while(!SPI_receive()) //wait for SD card to complete writing and get idle
     if(retry++ > 0xfffe){SD_CS_DEASSERT; return 1;}

   SPI_receive(); //extra 8 bits
   blockCounter++;
}

SPI_transmit(0xfd); //send 'stop transmission token'

retry = 0;
	   if(data == '~')
	   {
		  fileSize--;	//to remove the last entered '~' character
		  i--;

		  for(;i<512;i++)  //fill the rest of the buffer with 0x00
			buffer[i]= 0x00;

		  error = SD_writeSingleBlock (startBlock);

		  txString(_COM1, "data = ~\n");
		  break;
	   }
while(!SPI_receive()) //wait for SD card to complete writing and get idle
   if(retry++ > 0xfffe){SD_CS_DEASSERT; return 1;}

SD_CS_DEASSERT;
SPI_transmit(0xff); //just spend 8 clock cycle delay before reasserting the CS signal
SD_CS_ASSERT; //re assertion of the CS signal is required to verify if card is still busy

while(!SPI_receive()) //wait for SD card to complete writing and get idle
   if(retry++ > 0xfffe){SD_CS_DEASSERT; return 1;}
SD_CS_DEASSERT;

return 0;
}