//  Haybin_Wu
//  Shenitech-RD
//  2016.5
//  Built with IAR Embedded Workbench v6.2
//******************************************************************************
//  Modify by Qian Xianghong
//  2020.10
//  修改日志：将无线模块做成串口和RF双向透传模式。
//******************************************************************************
#include <msp430FR2433.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "FR2433-RFSX.h"
#include "RF_SX1276.h"

// 射频配置参数
lora_param_t Lora_Param;

#define TRAN_BUF_SIZE (1024)

// 用UA1串口做打印输出，方便调试
char printBuf[200];
void uart_print()
{
#if 0  // 打印串口的2个引脚用作MD0、MD1模式选择   
    char *p = printBuf;
    while(*p)
    {
        if(*p == '\n') // 换行前添加回车
        {
            while(!(UCA1IFG & UCTXIFG));
            UCA1TXBUF = '\r';
        }
        while(!(UCA1IFG & UCTXIFG));
        UCA1TXBUF = *p++;
    }
#endif
}

// 可变参数的宏定义
#define PRINTF(format, ...) \
{ \
    snprintf(printBuf, sizeof(printBuf), format, ##__VA_ARGS__); \
    uart_print(); \
}

// UA0接收上位机数据的buf
uint8_t UA0_RxBuf[TRAN_BUF_SIZE] = {0};
uint16_t UA0_RxBuf_Length = 0;
uint16_t UA0_RxBuf_offset = 0;
// UA0接收超时
volatile uint8_t UA0_Rx_Timeout = 1;

// RF接收数据的buf
uint8_t RF_RxBuf[TRAN_BUF_SIZE] = {0};
uint16_t RF_RxBuf_Length = 0;
uint16_t RF_RxBuf_offset = 0;
// RF接收超时标志
volatile uint8_t RF_Rx_Timeout = 1;

////////////////////////////////////////////////////////////////////////////////
// 主串口初始化
void UA0_Init(uint32_t baudrate)
{
    // Configure UART
    UCA0CTLW0 |=(UCSSEL__SMCLK+UCSWRST);//UCPEN+UCPAR+
    // Baud Rate calculation
    if(baudrate == 115200)
    {
        UCA0BR0 = 4;    // 8000000/16/115200//这位大于16 UCOS16位要置位
        UCA0BR1 = 0;    // Fractional portion = 0.44444
        UCA0MCTLW = 0x5500 | UCOS16 | UCBRF_5;//微调Baud Rate
    }
    else if(baudrate == 38400)
    {
        UCA0BR0 = 13;    // 8000000/16/38400 /这位大于16 UCOS16位要置位
        UCA0BR1 = 0;    // Fractional portion = 0.33333
        UCA0MCTLW = 0x8400 | UCOS16 | UCBRF_0;//微调Baud Rate
    }
    else
    {
        UCA0BR0 = 52;    // 8000000/16/9600 /这位大于16 UCOS16位要置位
        UCA0BR1 = 0;    // Fractional portion = 0.33333
        UCA0MCTLW = 0x4900 | UCOS16 | UCBRF_1;//微调Baud Rate
    }
    UCA0CTLW0 &= ~UCSWRST;                    // Initialize eUSCI
    UCA0IE |= UCRXIE;                         // Enable USCI_A0 RX interrupt
}

// 主串口应答（配置命令）
void UA0_Response(char *s)
{
    while(*s)
    {
        while(!(UCA0IFG & UCTXIFG));
        UCA0TXBUF = *s++;
    }
    // 等待发送结束
    while(!(UCA0IFG & UCTXCPTIFG));
    DelayMs(2);
}

////////////////////////////////////////////////////////////////////////////////
//主函数
////////////////////////////////////////////////////////////////////////////////
  int main(void)
{
    uint8_t sendCh;
    
    WDTCTL = (WDTPW | WDTHOLD);               // Stop WDT
    // Port Configuration all un-used pins to output low
    P1DIR = 0xFF; P2DIR = 0xFF; P3DIR = 0xFF;
    P1OUT = 0x00; P2OUT = 0x00; P3OUT = 0x00;
    PM5CTL0 &= ~LOCKLPM5;//开引脚功能

    // Configure DCO Clock
    //外部时钟源启动
    P2SEL0 |= (BIT0 | BIT1);                  // set XT1 pin as second function
    do
    {
        CSCTL7 &= ~(XT1OFFG | DCOFFG);      // Clear XT1 and DCO fault flag
        SFRIFG1 &= ~OFIFG;
    } while (SFRIFG1 & OFIFG);              // Test oscillator fault flag
    //上面清除标志有助于降低功耗

    __bis_SR_register(SCG0);                // disable FLL
    CSCTL3 |= SELREF__XT1CLK;              // 外部 32768hz reference source
    CSCTL0 = 0;                             // clear DCO and MOD registers
    CSCTL1 &= ~(DCORSEL_7);                 // Clear DCO frequency select bits first
    CSCTL1 |= DCORSEL_3;       //DCO=8Mhz
    CSCTL2 = FLLD_0 + 243;   // DCODIV = 8MHz
    __delay_cycles(3);
    __bic_SR_register(SCG0);                // enable FLL
    while(CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1)); // Poll until FLL is locked

    CSCTL4 = SELREF__XT1CLK + SELMS__DCOCLKDIV;// set XT1CLK(32768Hz) as ACLK source  &   MCLK/SMCLK=DCO

    //Timer0_A0 setup
    TA0CCTL0 = CCIE;                       // TACCR0 interrupt enabled
    TA0CCR0 = 32768 / 32;                 // 串口接收超时: 1000/32=31.25ms 
    TA0CTL = MC__STOP | TACLR;            // Stop mode, Clear counter

    //Timer1_A0 setup
    TA1CCTL0 = CCIE;                       // TACCR0 interrupt enabled
    TA1CCR0 = 32768 / 4;                 // RF接收超时: 1000/4=250ms 
    TA1CTL = MC__STOP | TACLR;            // Stop mode, Clear counter
    
    // 设置无线模块缺省参数
    Lora_Param.sof = 0xC2;
    Lora_Param.addr = 0xADF2; // 通信地址0xADF2
    Lora_Param.sf = 6;      // sf=12
    Lora_Param.baud = 3;    // 9600
    Lora_Param.cr = 0;      // cr=4/5
    Lora_Param.ch = 9;      // 479MHz
    Lora_Param.power = 1;  // 17dBm
    Lora_Param.freqcast = 0; // freqcast off
    Lora_Param.bw = 9;      // 500kHz
    Lora_Param.unicast = 0; // unicast off
            
    // Configure UART pins
    P1SEL1 &= ~(BIT4 | BIT5);                    // set 2-UART pin as second function
    P1SEL0 |= (BIT4 | BIT5);                    // set 2-UART pin as second function
    if(Lora_Param.baud == 7)
        UA0_Init(115200);
    else if(Lora_Param.baud == 5)
        UA0_Init(38400);
    else
        UA0_Init(9600);

#if 0  // 配置打印串口  
    // Configure UART pins
    P2SEL1 &= ~(BIT5 | BIT6);                    // set 2-UART pin as second function
    P2SEL0 |= (BIT5 | BIT6);                    // set 2-UART pin as second function
    // Configure UART
    UCA1CTLW0 |=(UCSSEL__SMCLK+UCSWRST);//UCPEN+UCPAR+
    // Baud Rate calculation
    UCA1BR0 = 4;    // 8000000/16/115200//这位大于16 UCOS16位要置位
    UCA1BR1 = 0;    // Fractional portion = 0.44444
    UCA1MCTLW = 0x5500 | UCOS16 | UCBRF_5;//微调Baud Rate
    UCA1CTLW0 &= ~UCSWRST;                    // Initialize eUSCI
    UCA1IE |= UCRXIE;                         // Enable USCI_A0 RX interrupt

    // 打印复位原因(电源引起，不包括看门狗)
    PRINTF("\nModule reseted: %04X\n", PMMIFG);

#else  // 配置MD0、MD1模式
    P2SEL1 &= ~(BIT3 | BIT5 | BIT6);                    // set 2-UART pin as GPIO
    P2SEL0 &= ~(BIT3 | BIT5 | BIT6);                    // set 2-UART pin as GPIO
    P2DIR &= ~(BIT5 | BIT6);                     // Input
    P2REN |= (BIT5 | BIT6);                      // enable pull
    P2OUT &= ~(BIT5 | BIT6);                     // pull-down
   
    P2DIR |= BIT3;                                // Output
    P2OUT |= BIT3;                              // Output high
#endif
    
    _EINT();

#if 0    
    // 打印复位原因(电源引起，不包括看门狗)
   RF_RxBuf[0] = PMMIFG >> 8;
   RF_RxBuf[1] = PMMIFG & 0xFF;
   RF_RxBuf_Length = 2;
   RF_RxBuf_offset = 0;
   UCA0IE |= UCTXIE;
   while(UCA0IE & UCTXIE);
#endif
    // 读寄存器，清除复位原因
    SYSRSTIV;
   
    //无线模块初始化
    uint8_t try_count = 3; //最多初始化3次
    while(try_count)
    {
        if(SX127x_initLora(&Lora_Param) == NORMAL) 
            break;
        try_count--;
    }          
    if(try_count == 0) //无线初始化失败处理
    { 
        //P3OUT ^= 0xC0;
        LPM4;
    }
  
    // 初始处于接收模式
    LSD_RF_RXmode(RF_PAYLOAD_LEN);
    // 默认发送信道
    sendCh = Lora_Param.ch;

    // 开启看门狗: 超时时间为2^27/SMCLK，在8000000主频下约为16s
    WDTCTL = (WDTPW | WDTCNTCL | WDTIS_1);

    while(1)
    {   
#if 1
        // TODO: 喂狗
        WDTCTL = (WDTPW | WDTCNTCL | WDTIS_1);

        // 配置模式
       if((P2IN & (BIT5 | BIT6)) == (BIT5 | BIT6))
       {
           if(UA0_RxBuf_Length - UA0_RxBuf_offset >= sizeof(Lora_Param))
           {                
               if(UA0_RxBuf[UA0_RxBuf_offset] == 0xC2)
               {
                    // 保存参数
                    memmove(&Lora_Param, UA0_RxBuf + UA0_RxBuf_offset, sizeof(Lora_Param));
                    // 颠倒地址高低字节
                    Lora_Param.addr = (Lora_Param.addr << 8) | (Lora_Param.addr >> 8);

                    //无线模块初始化
                    uint8_t try_count = 3; //最多初始化3次
                    while(try_count)
                    {
                        // 其它参数有变化，无线模块初始化
                        if(SX127x_initLora(&Lora_Param) == NORMAL) 
                            break;
                        try_count--;
                    }          
                    if(try_count == 0) //无线初始化失败处理
                    { 
                        //P3OUT ^= 0xC0;
                        LPM4;
                    }

                    // 默认处于接收模式
                    LSD_RF_RXmode(RF_PAYLOAD_LEN);
                    // 默认发送信道
                    sendCh = Lora_Param.ch;
                    // 应答配置命令
                    UA0_Response("OK\r\n");

                    // 改变串口波特率
                    if(Lora_Param.baud == 7)
                        UA0_Init(115200);
                    else if(Lora_Param.baud == 5)
                        UA0_Init(38400);
                    else
                        UA0_Init(9600);
               }
               
               UA0_RxBuf_offset = UA0_RxBuf_Length;
           }
       }
       // 透传模式
       else if((P2IN & (BIT5 | BIT6)) == 0)
#endif
       {
           if(UA0_RxBuf_Length > UA0_RxBuf_offset)
           {
                // 定点传输，指定目标地址和信道发送
               if(Lora_Param.unicast)      // 定点发送
               {
                   if(UA0_RxBuf_offset == 0 && UA0_RxBuf_Length > 3)
                        sendCh = UA0_RxBuf[2];
               }
               else if(Lora_Param.freqcast) // 指定信道发送
               {
                   if(UA0_RxBuf_offset == 0 && UA0_RxBuf_Length > 1)
                   {
                        sendCh = UA0_RxBuf[0];
                        Lora_Param.ch= UA0_RxBuf[1];
                        UA0_RxBuf_offset = 2; // 不发送第1发个字节
                   }
               }               

               if(UA0_RxBuf_Length - UA0_RxBuf_offset >= RF_PAYLOAD_LEN)
               {
                    LSD_RF_FreqSet(sendCh);
                    LSD_RF_SendPacket(UA0_RxBuf + UA0_RxBuf_offset, RF_PAYLOAD_LEN);
                    UA0_RxBuf_offset += RF_PAYLOAD_LEN;                    
                    PRINTF("Send packet\n");
                    
                    // 切换到接收模式
                    LSD_RF_FreqSet(Lora_Param.ch);
                    LSD_RF_RXmode(RF_PAYLOAD_LEN);

               }
               else if(UA0_Rx_Timeout)
               {
                    LSD_RF_FreqSet(sendCh);
                    LSD_RF_SendPacket(UA0_RxBuf + UA0_RxBuf_offset, UA0_RxBuf_Length - UA0_RxBuf_offset);
                    UA0_RxBuf_offset = UA0_RxBuf_Length;
                    PRINTF("Send packet\n");                    
                    
                    // 切换到接收模式
                    LSD_RF_FreqSet(Lora_Param.ch);
                    LSD_RF_RXmode(RF_PAYLOAD_LEN);
               }
           }
       }      

       if(UA0_Rx_Timeout && UA0_RxBuf_offset == UA0_RxBuf_Length)
           P2OUT |= BIT3;                                 // Output high
    }
}

// Port 1 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(PORT1_VECTOR))) Port_1 (void)
#else
#error Compiler not supported!
#endif
{
  uint8_t offset = 0;
  uint8_t len[1] = {0};
  uint8_t buf[RF_PAYLOAD_LEN];
  if(DIO0_IFG&DIO0_BIT)   //数据传输中断处理
  {
    // 清中断
    DIO0_IFG &= ~DIO0_BIT;

    // 读取RF数据
    LSD_RF_RxVariPacket(buf, len);   //接收可变数据包，如果速率为大速率，只能用接收固定数据包长度

    if(len[0] == 0)
        return;

    TA1CTL = MC__STOP | TACLR;            // 停止定时器，复位计数器
    TA1CTL = TASSEL__ACLK | MC__UP;       // 重新开始计时

    offset = 0;
    if(RF_Rx_Timeout) // 新的一组数据到来
    {
        RF_Rx_Timeout = 0;

        // 复位缓冲区
        RF_RxBuf_Length = 0;
        RF_RxBuf_offset = 0;

        if(Lora_Param.unicast)
        {
            // 定点传输，地址和信道校验失败          
            if(len[0] <= 3 || buf[2] != Lora_Param.ch || ((buf[0] << 8) | buf[1]) != Lora_Param.addr)
                return;
            // 前3个字符丢掉
            offset = 3;
            len[0] -= offset;
        }
    }

    PRINTF("Recv packet\n");

    // 透传模式
    if((P2IN & (BIT5 | BIT6)) == 0)
    {
      if(RF_RxBuf_Length + len[0] <= TRAN_BUF_SIZE)
      {
        memmove(RF_RxBuf + RF_RxBuf_Length, buf + offset, len[0]);
        // 中断方式向串口转发
        RF_RxBuf_Length += len[0];
        UCA0IE |= UCTXIE;
      }
    }
  }
}

// Timer0 A0 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer0_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(TIMER0_A0_VECTOR))) Timer0_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
   // 停止定时器，复位计数器
   TA0CTL = MC__STOP | TACLR;
   // 串口接收超时
   UA0_Rx_Timeout = 1;
}

// Timer1 A0 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = TIMER1_A0_VECTOR
__interrupt void Timer1_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(TIMER1_A0_VECTOR))) Timer1_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
   // 停止定时器，复位计数器
   TA1CTL = MC__STOP | TACLR; 
   // RF接收超时
   RF_Rx_Timeout = 1;
}

// UAR0 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_A0_VECTOR))) USCI_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
  // 接收中断  
  if((UCA0IE & UCRXIE) && (UCA0IFG & UCRXIFG))
  {
    uint8_t c = UCA0RXBUF;

    TA0CTL = MC__STOP | TACLR;            // 停止定时器，复位计数器
    TA0CTL = TASSEL__ACLK | MC__UP;       // 重新开始计时

    if(UA0_Rx_Timeout) // 新的一组数据到来
    {
        UA0_Rx_Timeout = 0;
        // 复位缓冲区
        UA0_RxBuf_Length = 0;
        UA0_RxBuf_offset = 0;
    }           
    
    if(UA0_RxBuf_Length < TRAN_BUF_SIZE)
    {
#if 1
        // 配置模式
        if((P2IN & (BIT5 | BIT6)) == (BIT5 | BIT6))
        {
            // 第1个字符必须为0xC2
            if(UA0_RxBuf_Length > 0 || c == 0xC2)
                UA0_RxBuf[UA0_RxBuf_Length++] = c;            
        }
        // 透传模式
        else if((P2IN & (BIT5 | BIT6)) == 0)
#endif            
        {
            // 主函数透传
            UA0_RxBuf[UA0_RxBuf_Length++] = c;
        }
        
        P2OUT &= ~BIT3;                                 // Output low    
    }
  }

  // 发送中断
  if((UCA0IE & UCTXIE) && (UCA0IFG & UCTXIFG))
  {
    UCA0TXBUF = RF_RxBuf[RF_RxBuf_offset++];   // 发送字符
    if(RF_RxBuf_offset >= RF_RxBuf_Length)     // 全部发送完
    {
        // 禁止中断
        UCA0IE &= ~UCTXIE;
    }
  }
}
