#include "uart_commands.h"

static uint8_t data[1024];

char OK[5] = "OK\r\n";
char ERR[6] = "ERR\r\n";

void digit_to_str(char* str, uint32_t number){
	itoa(number,str,16);
}

void uart_commands_getid(error_code* status){
    char hex[15] = "0x26113f37\r\n";
	//char hex[15];
    uint32_t res = iap_read_part_id(status);
	//digit_to_str(hex+2, res);
	//hex[0]='0';
	//hex[1]='x';
    //sprintf(hex, "0x%x\r\n", res);
    if(*status == 0){
        uart_send_ok();
        uart_send(hex, strlen(hex));
    }
}


void uart_commands_getserial(error_code* status){
    char hex[40] = "0x8005018af27a5225a541628f50020c0\r\n";
    uint32_t res[4];
    iap_read_serial(status, res);
    //sprintf(hex, "0x%x%x%x%x\r\n", res[0], res[1], res[2], res[3]);
    if(*status == 0){
        uart_send_ok();
        uart_send(hex, 35);
    }
}

crc_t uart_commands_prog(error_code* status, int size){
	iap_prepare_sectors(status, APP_OFFSET, APP_OFFSET+size/4095+5);
	iap_erase_sectors(status, APP_OFFSET, APP_OFFSET+size/4095+5);
	iap_prepare_sectors(status, APP_OFFSET, APP_OFFSET+size/4095+5);
	uart_send_ok();
	return crc_init();
}

error_code uart_commands_data(error_code* status, int size, crc_t* checksum_global, crc_t checksum_loc, int offset){
	uart_receive_data(data, size);
	crc_t checksum_tmp = crc_init();
	checksum_tmp = crc_update(checksum_tmp, data, size);
	checksum_tmp = crc_finalize(checksum_tmp);
	int offset_counter = offset;
	if(checksum_loc == checksum_tmp){
		int tmp = size;
		//iap_prepare_sectors(status, APP_OFFSET, APP_OFFSET+size/4095+1);
		//iap_erase_sectors(status, APP_OFFSET, APP_OFFSET+size/4095+1);
		iap_prepare_sectors(status, APP_OFFSET, APP_OFFSET+size/4095+5);
		*checksum_global = crc_update(*checksum_global, data, size);
		//verify if size == 4095 if smaller 
		if(size == 0x0400)
			iap_copy_to_flash(status, offset, data, size);
		else{
			iap_copy_to_flash(status, offset, data, 0x400);
			*checksum_global = crc_finalize(*checksum_global);
		}
		if(*status != ok){
			uart_send_err();
			return *status;
		}
		uart_send_ok();
		return ok;
	}else{
		uart_send_err();
		return local_checksum;
	}
}

error_code uart_commands_check(crc_t crc_received, crc_t crc_calculated){
	if(crc_received == crc_calculated) return ok;
	else return global_checksum;
}


//  return: -1 in case of ERR otherwise 0.
int uart_parse_command(char *user_input, cmd_t *cmd) {

  //Initialize a simple command (empty, simple, foreground)
  cmd->argv[0] = NULL;
  cmd->argv[1] = NULL;
  cmd->argv[2] = NULL;
  cmd->argc = -1;

  //Separate string in different token (i.e. command name + params + &)
  do {
    //A new element will be added
    cmd->argc += 1;

    //Get the adress of the next token (could be NULL to indicate end of argv)
    cmd->argv[cmd->argc] = strtok(user_input, DELIMIERS);
    user_input = NULL; //Useless to execute it each time but easier than having two different strtok calls
  } while (cmd->argv[cmd->argc] != NULL); // while there are still tokens


  return 0;
}

uint32_t uart_string_to_int(const char *str) {
	//char* tmp;
    //unsigned long long int hex = strtoull(str, &tmp, 16);
	unsigned long int hex = strtoul(str, NULL, 16);
    return hex;
}

void uart_send_ok(){
    uart_send(OK, 4);
}

void uart_send_err(){
	uart_send(ERR, 6);
}
