/*
File: main.c
Copyright 2016 Marcos Mori de Siqueira <mori.br@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
//#include <p18cxxx.h>
#include <p18f2520.h>
#include <delays.h>
#include <usart.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <i2c.h>
#include <timers.h>
#include "rda5807.h"
#include "hardwareprofile.h"
#include "LCDBlocking.h"
#include "TimeDelay.h"
#include "keypad.h"
#include "log.h"
#include "eeprom.h"
#include "rds.h"
#include "options.h"
#include "test.h"
#include <math.h>
#pragma config OSC = HS
#pragma config WDT = OFF
#pragma config LVP = OFF
#pragma config MCLRE = ON
#pragma config PWRT = ON
#pragma config PBADEN = OFF
#define MAX_VOLUME 0x0C //0x0F
#define SAVE_TIMEOUT 5000
#define BACK2IDLE_TIMEOUT 1000
#define MENU_TIMEOUT 50000
#define STATE_IDLE 0
#define STATE_VOLUME 1
#define STATE_MEMORY 2
#define STATE_MENU 3
#define STATE_LAST_BASIC 3
#define STATE_LAST 4
static BYTE mem_idx = 0;
static BYTE state = STATE_IDLE;
static LONG state_timeout = 0;
extern volatile RDSINFO rds;
static RDAINFO info;
typedef struct
{
RDA_MEMORY mem;
LONG mem_save_timeout;
BYTE enabled;
} SAVEINFO;
static SAVEINFO save_info = {{0},0,0};
static void update_lcd(void);
static void process_dn(void);
static void process_up(void);
static BYTE setup_memory(void);
void main(void)
{
char *c = 0;
DWORD counter = 0, read = 0;
BYTE evt;
DWORD ellapsed = 0;
BYTE btn_ok_pressed = 0;
CMCON = 0x07; // Comparators Off
CVRCON = 0; // voltage reference=off
ADCON1 = 0x0F; // Disable ALL adc channels, PDF page 226
LED1_TRIS = OUTPUT_PIN;
I2C_SCL_TRIS = OUTPUT_PIN;
I2C_SDA_TRIS = OUTPUT_PIN;
// Uart
OpenUSART(USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_CONT_RX & USART_BRGH_HIGH, 10);
LOG((ROMCHAR)"\r\n-------------------------------------------------\r\n");
KeypadInit();
LCDInit();
// Setup I2C
OpenI2C(MASTER, SLEW_OFF);
//SSPADD = 0x32; //100kHz Baud clock @20MHz
SSPADD = 0x0B;//400kHz Baud clock @20MHz
LCDErase();
strcpypgm2ram(c, (ROMCHAR)" STARTING ");
LCDWriteLine(1, c);
memset(save_info.mem.data, 0, sizeof(RDA_MEMORY));
//TEST_eeprom_reset();
if(!EEPROM_load_data(&save_info.mem))
{
LOG((ROMCHAR)"loading default config\r\n");
save_info.mem.flags = RDA_FLAG_RDS|RDA_FLAG_BASS;
save_info.mem.channel = 101.7;
save_info.mem.volume = 1;
//save_info.mem.memory[0] = 97.7;
//save_info.mem.memory[3] = 103.3;
//save_info.mem.memory[4] = 90.5;
}
LOG((ROMCHAR)"init\r\n");
RDA5807M_init();
RDA5807M_PowerON();
DelayMs(200);
// Setup radio
RDA5807M_SetVolume(save_info.mem.volume);
RDA5807M_SetFrequency(save_info.mem.channel);
RDA5807M_BassBoost(save_info.mem.flags & RDA_FLAG_BASS);
RDA5807M_Mono(save_info.mem.flags & RDA_FLAG_MONO);
RDA5807M_RDS(save_info.mem.flags & RDA_FLAG_RDS);
while(1)
{
LED1 = 0;
if(counter++ > 3000)
{
counter = 0;
LED1 = 1;
DelayMs(10);
}
evt = GetButtonsEvents();
if(evt != EVENT_NOTHING)
{
if(evt == EVENT_UP_BUTTON_PUSHED)
{
if(state != STATE_MENU)
{
//LOG((ROMCHAR)"up %d\r\n", state);
if(++state >= STATE_LAST_BASIC)
state = STATE_IDLE;
//LOG((ROMCHAR)"up %d\r\n", state);
if(state == STATE_MEMORY)
mem_idx = setup_memory();
if(state > STATE_IDLE)
state_timeout = BACK2IDLE_TIMEOUT;
else
{
state_timeout = 0;
rds.ps_valid = 1;
rds.rt_valid = 1;
}
}
else
{
state_timeout = MENU_TIMEOUT;
MENU_run(MENU_UP);
}
}
else if(evt == EVENT_DN_BUTTON_PUSHED)
{
if(state != STATE_MENU)
{
//LOG((ROMCHAR)"dn %d\r\n", state);
if(--state >= 0xFF)
state = STATE_IDLE;
//LOG((ROMCHAR)"dn %d\r\n", state);
if(state > STATE_IDLE)
state_timeout = BACK2IDLE_TIMEOUT;
else
{
state_timeout = 0;
rds.ps_valid = 1;
rds.rt_valid = 1;
}
}
else
{
state_timeout = MENU_TIMEOUT;
MENU_run(MENU_DOWN);
}
}
else if(evt == EVENT_LEFT_BUTTON_PUSHED)
{
//LOG((ROMCHAR)"left\r\n");
if(state == STATE_MENU)
{
state_timeout = MENU_TIMEOUT;
MENU_run(MENU_LEFT);
}
else
process_dn();
}
else if(evt == EVENT_RIGHT_BUTTON_PUSHED)
{
//LOG((ROMCHAR)"right\r\n");
if(state == STATE_MENU)
{
state_timeout = MENU_TIMEOUT;
MENU_run(MENU_RIGHT);
}
else
process_up();
}
else if(evt == EVENT_OK_BUTTON_PUSHED)
{
btn_ok_pressed = 1;
ellapsed = 0;
}
else if(evt == EVENT_MENU_BUTTON_PUSHED)
{
LOG((ROMCHAR)"menu\r\n");
if(state == STATE_MENU)
state_timeout = 1; // change to idle
else
{
MENU_init(&save_info.mem);
state = STATE_MENU;
state_timeout = MENU_TIMEOUT;
}
}
else if(evt == EVENT_OK_BUTTON_RELEASED)
{
LOG((ROMCHAR)"OK released\r\n");
btn_ok_pressed = 0;
if(ellapsed < 250)
{
if(state == STATE_MENU)
{
if(MENU_run(MENU_OK))
{
save_info.enabled = 1;
state_timeout = 400;
}
else
state_timeout = MENU_TIMEOUT;
}
else
{
switch(state)
{
case STATE_IDLE:
RDA5807M_Mute();
break;
case STATE_MEMORY:
if(save_info.mem.memory[mem_idx] > 0)
{
RDA5807M_SetFrequency(save_info.mem.memory[mem_idx]);
state_timeout = 1; // change to idle
}
break;
}
}
}
}
}
if(read++ > 1)
{
read = 0;
RDA5807M_Read(&info);
update_lcd();
}
if(save_info.mem_save_timeout > 0)
{
if(--save_info.mem_save_timeout <= 0)
{
save_info.mem_save_timeout = 0;
LOG((ROMCHAR)"SAVE DATA EEPROM\r\n");
LOG((ROMCHAR)"chann %d\r\n", (int)save_info.mem.channel);
EEPROM_save_data(&save_info.mem);
}
}
// Dont back to IDLE while pressing memory saving button
if(!btn_ok_pressed && state_timeout > 0)
{
if(--state_timeout <= 0)
{
LOG((ROMCHAR)"IDLE\r\n");
state_timeout = 0;
rds.ps_valid = 1;
rds.rt_valid = 1;
state = STATE_IDLE;
}
}
ellapsed++;
if(btn_ok_pressed && ellapsed > 250)
{
save_info.mem.memory[mem_idx] = save_info.mem.channel;
state_timeout = 1;
}
}
}
static void process_up(void)
{
switch(state)
{
case STATE_IDLE:
save_info.enabled = 1;
RDA5807M_SeekUp();
break;
case STATE_VOLUME:
if(++save_info.mem.volume >= MAX_VOLUME)
save_info.mem.volume = MAX_VOLUME;
state_timeout = BACK2IDLE_TIMEOUT;
RDA5807M_SetVolume(save_info.mem.volume);
break;
case STATE_MEMORY:
if(++mem_idx >= MAX_CHANNEL_MEM)
mem_idx = MAX_CHANNEL_MEM-1;
state_timeout = BACK2IDLE_TIMEOUT;
break;
}
}
static void process_dn(void)
{
switch(state)
{
case STATE_IDLE:
save_info.enabled = 1;
RDA5807M_SeekDown();
break;
case STATE_VOLUME:
if(--save_info.mem.volume >= 0xFF)
save_info.mem.volume = 0;
state_timeout = BACK2IDLE_TIMEOUT;
RDA5807M_SetVolume(save_info.mem.volume);
break;
case STATE_MEMORY:
if(--mem_idx >= 0xFF)
mem_idx = 0;
state_timeout = BACK2IDLE_TIMEOUT;
break;
}
}
static void update_volume(void)
{
BYTE i = 0;
strcpypgm2ram(LCDText[1], (ROMCHAR)"VOL ");
for(; i < save_info.mem.volume; ++i)
strcatpgm2ram(LCDText[1], (ROMCHAR)"\xFF");
}
static BYTE setup_memory(void)
{
BYTE i = 0;
for(; i < MAX_CHANNEL_MEM; ++i)
{
if(save_info.mem.memory[i] > 0 && save_info.mem.memory[i] == info.freq)
{
return i;
}
}
return 0xFF;
}
static void update_lcd(void)
{
int num, dec;
char c[17] = {0};
BYTE memidx = 0;
char m[1] = {' '};
char m1[3] = {' ',' ', 0};
static BYTE size = 0;
static BYTE pos = 0;
static WORD ps = 0;
if(state < STATE_LAST_BASIC)
{
// Draw line 1
if(state == STATE_MEMORY)
{
// Display current memory station
strncpypgm2ram(LCDText[0], (ROMCHAR)" FM ---.- ", 16);
if(save_info.mem.memory[mem_idx] > 0)
{
num = save_info.mem.memory[mem_idx];
dec = (int)floor(((save_info.mem.memory[mem_idx] - num) * 100)/10);
if(dec % 2 == 0) dec += 1;
sprintf(c, (ROMCHAR)" FM %3d.%1d ", num, dec);
strncpy(LCDText[0], c, 16);
}
}
else
{
// Display station currently tunned
strncpypgm2ram(LCDText[0], (ROMCHAR)" \xA5\xA5 SCANNING \xA5\xA5 ", 16);
//if(info.fmtrue && info.tuneok)
//{
num = info.freq;
dec = (int)floor(((info.freq - num) * 100)/10);
if(dec % 2 == 0) dec += 1;
memidx = setup_memory();
if(memidx != 0xFF) {
itoa(memidx+1, m);
m1[0] = 'M';
m1[1] = m[0];
}
if(info.stereo)
sprintf(c, (ROMCHAR)"%1d %s FM %3d.%1d\xA5", info.rssi, m1, num, dec);
else
sprintf(c, (ROMCHAR)"%1d %s FM %3d.%1d ", info.rssi, m1, num, dec);
strncpy(LCDText[0], c, 16);
if(info.fmtrue && info.tuneok)
{
// Start save timer
if(save_info.enabled)
{
save_info.mem.channel = info.freq;
save_info.mem_save_timeout = SAVE_TIMEOUT;
save_info.enabled = 0;
}
}
}
switch(state)
{
case STATE_IDLE:
{
if(!rds.use_rt && rds.ps_valid)
{
rds.ps_valid = 0;
memset(LCDText[1], ' ', 16);
strncpy(&LCDText[1][4], rds.ps_copy, 8);
}
else
{
if(rds.rt_valid)
{
rds.rt_valid = 0;
memset(LCDText[1], ' ', 16);
size = strlen(rds.rt_copy);
pos = 0;
ps = 0;
strncpy(LCDText[1], rds.rt_copy, size > 16 ? 16 : size);
}
else
{
if(rds.use_rt && ps++ > 30)
{
ps = 0;
if(size < 16)
strncpy(LCDText[1], rds.rt_copy, size > 16 ? 16 : size);
else
strncpy(LCDText[1], &rds.rt_copy[pos++], (size - pos) > 16 ? 16 : size);
}
}
}
}
break;
case STATE_VOLUME:
update_volume();
break;
case STATE_MEMORY:
{
switch(mem_idx)
{
case 0:
strncpypgm2ram(LCDText[1], (ROMCHAR)"MEM \x0A51 2 3 4 5 6", 16);
break;
case 1:
strncpypgm2ram(LCDText[1], (ROMCHAR)"MEM 1 \x0A52 3 4 5 6", 16);
break;
case 2:
strncpypgm2ram(LCDText[1], (ROMCHAR)"MEM 1 2 \x0A53 4 5 6", 16);
break;
case 3:
strncpypgm2ram(LCDText[1], (ROMCHAR)"MEM 1 2 3 \x0A54 5 6", 16);
break;
case 4:
strncpypgm2ram(LCDText[1], (ROMCHAR)"MEM 1 2 3 4 \x0A55 6", 16);
break;
case 5:
strncpypgm2ram(LCDText[1], (ROMCHAR)"MEM 1 2 3 4 5 \x0A56", 16);
break;
default:
LOG((ROMCHAR)"ERR %d\r\n", mem_idx);
mem_idx = 0;
break;
}
}
break;
}
}
else
{
MENU_draw();
}
LCDUpdate();
}