/**

* @UART

*/


// JP2 pin2 (T2OUT) connected to pin3 of COM-port (through the FTDI)

// thus the configuration for the USART1 (not the USART0)


#include "myUart.h"


unsigned char RS232_ReadChar(void) {

// Wait until a data is available

   while (!(UCSR0A & (1 << RXC0)))

   {

       asm volatile("nop");

   }

   return UDR0;

}


unsigned char RS485_ReadChar(void) {

   while (!(UCSR1A & (1 << RXC1))) {

       asm volatile("nop");

       asm volatile("nop");

       asm volatile("nop");

   }

   return UDR1;

}


// This function writes the given "data" to the USART

// which transmits it via TX line

void RS232_WriteChar(unsigned char data) {

// Wait until the transmitter is ready

   while (!(UCSR0A & (1 << UDRE0))) 

   {

       asm volatile("nop");

   }

// Now write the data to USART buffer

   UDR0 = data;       

}


void RS485_WriteChar(unsigned char data) {

   while (!(UCSR1A & (1 << UDRE1))) {

       asm volatile("nop");

   }

   UDR1 = data;

}


void displayTelegram(char *message, uint8_t* myTelegram) {

   uint8_t i;


   // display telegram

   RS232_putstring("\r\n");

   RS232_putstring(message);

   for (i = 0; i < 14; i++) {

       print_hexByte(myTelegram[i]);

       RS232_putstring(" ");

   }

   RS232_putstring("\r\n");

}


uint8_t* RS485_QueryTelegram(uint8_t* myTelegram) {


   // function is blocking when MM not connected,

   // thus a time-out loop must be added

   uint8_t i;


   // send telegram

   for (i = 0; i < 14; i++) {

       RS485_WriteChar(myTelegram[i]);

   }


   // clean the buffer

   for (i = 0; i < 14; i++) {

       myTelegram[i] = 0xFF;

   }


   // read telegram

   for (i = 0; i < 14; i++) {

       // must connect the MM first

       myTelegram[i] = RS485_ReadChar();

   }

   return myTelegram;

}


void RS232_putstring(char* StringPtr) {

   while (*StringPtr != 0x00) {

       RS232_WriteChar(*StringPtr);

       StringPtr++;

   }

}


void RS485_putstring(char* StringPtr) {

   while (*StringPtr != 0x00) {

       RS485_WriteChar(*StringPtr);

       StringPtr++;

   }

}


//USART0

void RS232_init(uint32_t baudrate) {

   uint8_t prescaller = ((F_CPU / (baudrate * 16UL))) - 1;

   UBRR0H = (uint8_t) (prescaller >> 8);

   UBRR0L = (uint8_t) (prescaller);


   UCSR0B |= (1 << RXEN0) | (1 << TXEN0);

   UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01);

}


// USART1: RS485 parity for the MM is always EVEN!!!

void RS485_init(uint32_t baudrate) {

   uint8_t prescaller = ((F_CPU / (baudrate * 16UL))) - 1;

   UBRR1H = (uint8_t) (prescaller >> 8);

   UBRR1L = (uint8_t) (prescaller);


   UCSR1B |= (1 << RXEN1) | (1 << TXEN1);        // Enable receiver and transmitter

   UCSR1C |= (1 << UCSZ10) | (1 << UCSZ11);    // Table 80. UCSZn Bits Settings (page 191)

   UCSR1C |= (1 << UPM11);

   UCSR1C &= ~(1 << UPM10);                // even parity enabled

   UCSR1C &= ~(1 << USBS0);                // Sets 1 stop bits

   UCSR1C &= ~(1 << UMSEL1);                //asynchronous mode

}


////////////////////////////////////////////////////////////////////////////////


/**

* @USS protocol

*/


#include "usscalc.h"


//ppo1: stx, lge, adr, (word1: pkeHi, pkeLo), (word2: indHi, indLo),

// (word3: pwe1Hi, pwe1Lo), (word4: pwe2Hi, pwe2Lo), pzd1Hi, pzd1Lo, bcc

#define ppo 1

#define mirror 0

#define pkw 0


// AK: bit 15-12 (0-f << 1111 0000 0000 0000) - Auftrag oder Antwort-ID

// 1 Request parameter

// 2 Change parameter value (word) [RAM only]

// 3 Change parameter value (double word) [RAM only]

// 4 Request description element

#define AK 0x00


// SP: bit 11 (0000 1000 0000 0000) - Spontanmeldebearbeitung

#define mySP 0


// PNU: bit 0-10 (0000 0111 1111 1111) - parameter-nummer

#define PNU 0x12bc


// PNEex: bit 15-12

#define PNUex 0x00


// IDX: bit 0-7 (1111 1111) - array index (subindex)

#define IDX 0x00


uint8_t calcBCC() {

   uint8_t previous = 0;

   uint8_t i = 0;

   do {

       previous = previous ^ myTelegram[i];     // XOR

       i++;

   } while (i < 13);


   return previous;

}


// ver 2.04

void prepTelegram(uint16_t myPNU) {


   // stx, lge, adr,

   // pke: pkeHi, pkeLo,

   // ind: indHi, indLo,

   // pwe1: pwe1Hi, pwe1Lo,

   // pwe2: pwe2Hi, pwe2Lo,

   // pzd1: pzd1Hi, pzd1Lo,

   // bcc


   myTelegram[0] = 0x02;            // indicates the start of a message

   myTelegram[1] = 0x0c;            // length


   // address: the number of RS485 slave-node

   myTelegram[2] = (0x00 | (mirror << 6));


   // PKE: parameter number (PNU)

   myPNU = myPNU | 0x1000;          // set 'response' bit

   myTelegram[3] = ((0 | myPNU | (AK << 12) | (mySP << 11)) & 0xff00) >> 8;

   // AK

   myTelegram[4] = (0 | myPNU | (AK << 12) | (mySP << 11)) & 0x00ff;


   // IND: for MicroMaster non-significant

   myTelegram[5] = ((PNUex << 12) & 0xff00) >> 8;

   myTelegram[6] = IDX & 0x00ff;          // command


   // PWE1: 1st parameter value, high-order word

   myTelegram[7] = 0x00;

   myTelegram[8] = 0x00;


   // PWE2: 2nd parameter value, low-order word

   myTelegram[9] = 0x00;

   myTelegram[10] = 0x00;


   // PZD1: control status word

   myTelegram[11] = 0x00;

   myTelegram[12] = 0x00;


   // control sum

   myTelegram[13] = calcBCC();

}


uint16_t getValue(uint16_t myParam) {

   uint8_t *mmResponsePtr;

   uint16_t myShort;


   prepTelegram(myParam);

   // send query and get response (14 bytes)

   mmResponsePtr = RS485_QueryTelegram(myTelegram);

   

   // bytes [7] and [8] are the response value

   myShort = (mmResponsePtr[7] << 8) | mmResponsePtr[8];


   return myShort;

}


uint16_t * getAllValues(uint16_t* mmParametersArr, uint8_t length) {

   uint8_t i;

   static uint16_t myValueArray[127];

   for (i = 0; i < length; i++) {

       myValueArray[i] = getValue(mmParametersArr[i]);

   }

   heartbeat++;        // still alive

   return myValueArray;

}