//
// Name: ATVRxController.c
//
//
// Revision History:
//
// M. Gray 4 Sep 2003 V1.0 Initial release.
//
// M. Gray 27 Mar 2004 V1.1 Updates based on ham fest display and ANSR-17 flight.
//
//
// COPYRIGHT (c) 2003-04 Michael Gray, KD7LMO
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// Hardware specific configuration.
#include <18f252.h>
#device ADC=10
#fuses HS,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP
// These compiler directives set the clock, I/O ports, RS-232, and I2C interfaces.
#use delay(clock=3686400)
#use fast_io(B)
#use fast_io(C)
#use rs232(baud=38400, xmit=PIN_C6, rcv=PIN_C7)
#use i2c (master, scl=PIN_C0, sda=PIN_C1)
// We define types that are used for all variables. These are declared
// because each processor has a different sizes for int and long.
typedef int int8_t;
typedef unsigned int uint8_t;
typedef signed long int16_t;
typedef unsigned long uint16_t;
typedef int32 int32_t;
typedef unsigned int32 uint32_t;
// PROGRAMMING NOTE: Since we don't have embedded C++ for this processor,
// we try to use C in a manner that emulates classes and methods. Each method
// and variable is prefaced by the name of the class. The classes
// have a method that acts as a constructor and sometimes a destructor.
// Even though variables are declared as global, they are only accessed
// through the appropriate class method. The order of the classes and
// variables is not important in the application because we only access
// the class through a method.
// Prototypes for all methods.
uint8_t adcGetAGC();
uint8_t adcGetBusVolt();
void adcInit();
void adcUpdate();
void cat524Write (uint8_t port, uint8_t data);
uint16_t fileGetFreq();
void fileSetFreq (uint16_t freq);
void fileUpdateEEPROM (uint8_t index, uint8_t value);
void guiInit();
void guiSetBar(uint8_t value);
void guiSetBusVoltage (uint8_t voltage);
void guiSetFreq (uint16_t freq);
void ioInit();
void ioInterrupt();
boolean ioIsSW1Pushed();
boolean ioIsSW2Pushed();
boolean ioIsSW3Pushed();
void lcdChar (uint8_t value);
void lcdCommand (uint8_t command);
void lcdCursor (uint8_t x, uint8_t y);
void lcdInit();
void lcdString(char *string);
void lcdText (uint8_t x, uint8_t y, char *text);
void lcdWrite (uint8_t data);
void sysGetLCDModeText (uint8_t mode, char *text);
void sysGetVersion (char *version);
void sysInit();
void sysSetFreq (uint16_t freq);
void timerInit();
void timerInterrupt();
boolean timerIsUpdated();
boolean tunerIsLocked();
void tunerSetFreq(uint16_t freq);
/*
* Class to handle the ADC.
*/
// Accumulators that store a filter version of the bus and AGC voltage.
uint16_t adcBusVoltage, adcAGC;
// ADC channels for the desired measurements.
#define ADC_MAINBUS 0
#define ADC_AGC 2
/**
* Get the AGC value in the range of 0 to 15 where 0 is -80dBm
*
* @return agc
*/
uint8_t adcGetAGC()
{
uint8_t agc;
// Scale 1 - 4 volts on the AGC to equal 0 - 15.
agc = (uint8_t) (adcAGC / 82);
if (agc < 5)
return 0;
if (agc > 15)
return 15;
return agc - 4;
}
/**
* Get the main bus voltage in 0.1 volt resolution.
*
* @return voltage in 0.1 volt steps
*/
uint8_t adcGetBusVolt()
{
// Transfer function. 0.4 is the reverse polarity diode drop
// x * 494 * 3 * 1
// ---- --
// 1024 80
return (uint8_t) ((uint32_t) (adcBusVoltage) * 741l / 40960l) + 4;
}
/**
* Constructor.
*/
void adcInit()
{
uint8_t i;
// Setup the ADC.
setup_adc_ports( ALL_ANALOG );
setup_adc( ADC_CLOCK_DIV_32 );
// Zero the ADC filters.
adcBusVoltage = 0;
adcAGC = 0;
// Charge the ADC filters.
for (i = 0; i < 32; ++i)
adcUpdate();
}
/**
* Read and filter the ADC channels for bus voltage and internal temperature.
*/
void adcUpdate()
{
// Filter the analog values using a single pole low pass filter.
set_adc_channel(ADC_AGC);
delay_us(20);
adcAGC = read_adc() + adcAGC - (adcAGC >> 1);
set_adc_channel(ADC_MAINBUS);
delay_us(20);
adcBusVoltage = read_adc() + adcBusVoltage - (adcBusVoltage >> 3);
}
/*
* Class to handle the EEPROM file system.
*/
enum FILE_SYSTEM_MAP
{
FILE_MSB_MAGIC = 0x00,
FILE_LSB_MAGIC,
FILE_FREQ_MSB,
FILE_FREQ_LSB,
FILE_BACK_LIGHT,
FILE_COLOR,
FILE_BRIGHT,
FILE_CONT,
FILE_TINT,
FILE_LCD_MODE
};
#define FILE_MSB_MAGIC_DEFAULT 0x43
#define FILE_LSB_MAGIC_DEFAULT 0xcf
/**
* Get the back light setting from the file system.
*
* @return back light PWM
*/
uint8_t fileGetBackLightPWM()
{
return read_eeprom (FILE_BACK_LIGHT);
}
/**
* Get the color setting from the file system.
*
* @return color setting
*/
uint8_t fileGetColor()
{
return read_eeprom (FILE_COLOR);
}
/**
* Get the color setting from the file system.
*
* @return color setting
*/
uint8_t fileGetBright()
{
return read_eeprom (FILE_BRIGHT);
}
/**
* Get the color setting from the file system.
*
* @return color setting
*/
uint8_t fileGetContrast()
{
return read_eeprom (FILE_CONT);
}
/**
* Get the color setting from the file system.
*
* @return color setting
*/
uint8_t fileGetTint()
{
return read_eeprom (FILE_TINT);
}
/**
* Get the LCD screen mode.
*
* @return LCD screen mode
*/
uint8_t fileGetLCDMode()
{
return read_eeprom (FILE_LCD_MODE);
}
/**
* Get the frequency in MHz from the EEPROM file system.
*
* @return freq in MHz
*/
uint16_t fileGetFreq()
{
return ((uint16_t) read_eeprom (FILE_FREQ_MSB) << 8) | (uint16_t) read_eeprom (FILE_FREQ_LSB);
}
/**
* Initialize the file system.
*
*
* @return true if file system valid; otherwise false
*/
boolean fileInit()
{
if (read_eeprom(FILE_MSB_MAGIC) == FILE_MSB_MAGIC_DEFAULT && read_eeprom(FILE_LSB_MAGIC) == FILE_LSB_MAGIC_DEFAULT)
return true;
fileUpdateEEPROM (FILE_MSB_MAGIC, FILE_MSB_MAGIC_DEFAULT);
fileUpdateEEPROM (FILE_LSB_MAGIC, FILE_LSB_MAGIC_DEFAULT);
return false;
}
/**
* Store the tuner frequency in MHz in the EEPROM file system.
*
* @param freq in MHz
*/
void fileSetFreq (uint16_t freq)
{
fileUpdateEEPROM (FILE_FREQ_MSB, freq >> 8);
fileUpdateEEPROM (FILE_FREQ_LSB, freq & 0xff);
}
/**
* Store the back light PWM <b>value</b> in the file system.
*/
void fileSetBackLightPWM (uint8_t value)
{
fileUpdateEEPROM (FILE_BACK_LIGHT, value);
}
/**
* Store the color <b>value</b> in the file system.
*/
void fileSetColor (uint8_t value)
{
fileUpdateEEPROM (FILE_COLOR, value);
}
/**
* Store the color <b>value</b> in the file system.
*/
void fileSetBright (uint8_t value)
{
fileUpdateEEPROM (FILE_BRIGHT, value);
}
/**
* Store the color <b>value</b> in the file system.
*/
void fileSetContrast (uint8_t value)
{
fileUpdateEEPROM (FILE_CONT, value);
}
/**
* Store the color <b>value</b> in the file system.
*/
void fileSetTint (uint8_t value)
{
fileUpdateEEPROM (FILE_TINT, value);
}
/**
* Store the color <b>value</b> in the file system.
*/
void fileSetLCDMode (uint8_t value)
{
fileUpdateEEPROM (FILE_LCD_MODE, value);
}
void fileUpdateEEPROM (uint8_t index, uint8_t value)
{
if (read_eeprom (index) == value)
return;
write_eeprom (index, value);
}
/*
* Class to handle the user interface.
*/
/**
* Display the applicatino title and version.
*/
void guiVersion()
{
char buffer[20];
// Display the application name and version information on the LCD.
sysGetVersion (buffer);
lcdText (2, 1, buffer);
}
/**
* Display the labels.
*/
void guiLabel()
{
char buffer[20];
strcpy (buffer, "Freq xxxxMHz");
lcdText (1, 1, buffer);
strcpy (buffer, "Sig");
lcdText (1, 2, buffer);
}
/**
* Set the AGC bar graph.
*
* @param agc level in the range 0 to 15.
*/
void guiSetAGC (uint8_t agc)
{
uint8_t i;
char buffer[17];
// Draw solid blocks for each MSB in the age value.
for (i = 0; i < agc && i < 16; ++i)
buffer[i] = '\377';
// Fill in the rest with blanks.
while (i < 16)
buffer[i++] =' ';
// NULL terminate the string.
buffer[16] = 0;
// Now display it.
lcdText (5, 2, buffer);
}
/**
* Set an indicator bar on the bottom line of the 2 x 20 LCD display
* that represents <b>value</b>.
*
* @param value to display in the range 0 to 255
*/
void guiSetBar(uint8_t value)
{
uint8_t i;
lcdCursor (1, 2);
for (i = 0; i < 20; ++i)
lcdChar (' ');
lcdCursor (1 + (uint8_t) ((uint16_t) value * 10l / 128l), 2);
lcdChar ('\377');
}
/**
* Display the bus voltage.
*
* @param voltage in units of 0.1 volts
*/
void guiSetBusVoltage (uint8_t voltage)
{
char buffer[10];
sprintf (buffer, "%02d.%d", voltage / 10, voltage % 10);
lcdText (1, 2, buffer);
}
/**
* Display the frequency.
*
* @param frequency in MHz
*/
void guiSetFreq (uint16_t freq)
{
char buffer[10];
sprintf (buffer, "%ld", freq);
lcdText (6, 1, buffer);
}
/*
* Class to handle local I/O.
*/
boolean ioLastState1, ioLastState2, ioLastState3, ioTrigger1, ioTrigger2, ioTrigger3;
uint8_t ioPort0, ioPort1;
// Port 0 bit map.
#define IO_SCAN_DOWN 0x01
#define IO_SCAN_LEFT 0x02
#define IO_MODE_1 0x04
#define IO_MODE_2 0x08
#define IO_MODE_3 0x10
#define IO_MODE_MASK 0x1c
#define IO_MODE_SHIFT 2
#define IO_COMP_VIDEO 0x20
// Port 1 bit map.
#define IO_CAT524_PROG 0x01
#define IO_CAT524_DI 0x02
#define IO_CAT524_CS 0x04
#define IO_CAT524_CLK 0x08
#define IO_LED 0x10
void ioUpdatePorts()
{
i2c_start();
i2c_write(0x40);
i2c_write(0x00);
i2c_write(ioPort0);
i2c_write(ioPort1);
i2c_stop();
i2c_start();
i2c_write(0x40);
i2c_write(0x02);
i2c_write(ioPort0);
i2c_write(ioPort1);
i2c_stop();
}
void ioReadPort()
{
uint8_t value;
// Tell the MCP23016 we want to access the GP0 and GP1 registers.
i2c_start();
i2c_write(0x40);
i2c_write(0x00);
i2c_stop();
// Read the contents of the register.
i2c_start();
i2c_write(0x41);
value = i2c_read();
value = i2c_read();
i2c_stop();
// Check for changes in the input state and set a flag for high to low transitions.
// Since this routine is only called every 50mS, we will automatically debounce the switch.
if (ioLastState1 != ((value & 0x20) == 0x020 ? TRUE : FALSE)) {
if (ioLastState1)
ioTrigger1 = TRUE;
ioLastState1 = ~ioLastState1;
} // END if
if (ioLastState2 != ((value & 0x40) == 0x040 ? TRUE : FALSE)) {
if (ioLastState2)
ioTrigger2 = TRUE;
ioLastState2 = ~ioLastState2;
} // END if
if (ioLastState3 != ((value & 0x80) == 0x080 ? TRUE : FALSE)) {
if (ioLastState3)
ioTrigger3 = TRUE;
ioLastState3 = ~ioLastState3;
} // END if
}
/**
* Constructor.
*/
void ioInit()
{
// Initial output port settings.
ioPort0 = 0x00;
ioPort1 = 0x00;
ioLastState1 = FALSE;
ioLastState2 = FALSE;
ioLastState3 = FALSE;
ioTrigger1 = FALSE;
ioTrigger2 = FALSE;
ioTrigger3 = FALSE;
// Specify the port I/O direction.
i2c_start();
i2c_write(0x40);
i2c_write(0x06);
i2c_write(0x00);
i2c_write(0xe0);
i2c_stop();
ioUpdatePorts();
}
void ioSetCAT524Prog (boolean state)
{
if (state)
ioPort1 |= IO_CAT524_PROG;
else
ioPort1 &= ~IO_CAT524_PROG;
ioUpdatePorts();
}
void ioSetCAT524Data (boolean state)
{
if (state)
ioPort1 |= IO_CAT524_DI;
else
ioPort1 &= ~IO_CAT524_DI;
ioUpdatePorts();
}
void ioSetCAT524CS (boolean state)
{
if (state)
ioPort1 |= IO_CAT524_CS;
else
ioPort1 &= ~IO_CAT524_CS;
ioUpdatePorts();
}
void ioSetCAT524Clk (boolean state)
{
if (state)
ioPort1 |= IO_CAT524_CLK;
else
ioPort1 &= ~IO_CAT524_CLK;
ioUpdatePorts();
}
void ioScanDown (boolean state)
{
if (state)
ioPort0 |= IO_SCAN_DOWN;
else
ioPort0 &= ~IO_SCAN_DOWN;
ioUpdatePorts();
}
void ioScanLeft (boolean state)
{
if (state)
ioPort0 |= IO_SCAN_LEFT;
else
ioPort0 &= ~IO_SCAN_LEFT;
ioUpdatePorts();
}
void ioCompVideo (boolean state)
{
if (state)
ioPort0 |= IO_COMP_VIDEO;
else
ioPort0 &= ~IO_COMP_VIDEO;
ioUpdatePorts();
}
void ioSetMode (uint8_t mode)
{
ioPort0 = (ioPort0 & ~IO_MODE_MASK) | (mode << IO_MODE_SHIFT);
ioUpdatePorts();
}
void ioSetLED (boolean state)
{
if (state)
ioPort1 &= ~IO_LED;
else
ioPort1 |= IO_LED;
ioUpdatePorts();
}
/**
* Determine if switch 1 was pushed. This is a one shot method that
* debounces the switch contacts.
*
* @return true if pushed; otherwise false
*/
boolean ioIsSW1Pushed()
{
if (ioTrigger1) {
ioTrigger1 = FALSE;
return TRUE;
}
return FALSE;
}
/**
* Determine if switch 2 was pushed. This is a one shot method that
* debounces the switch contacts.
*
* @return true if pushed; otherwise false
*/
boolean ioIsSW2Pushed()
{
if (ioTrigger2) {
ioTrigger2 = FALSE;
return TRUE;
}
return FALSE;
}
/**
* Determine if switch 3 was pushed. This is a one shot method that
* debounces the switch contacts.
*
* @return true if pushed; otherwise false
*/
boolean ioIsSW3Pushed()
{
if (ioTrigger3) {
ioTrigger3 = FALSE;
return TRUE;
}
return FALSE;
}
#define CAT524_COLOR 0x00
#define CAT524_BRIGHT 0x02
#define CAT524_CONT 0x01
#define CAT524_TINT 0x03
/**
* Set the analog <b>port</b> to the value <b>data</b> in the range 0 to 255.
*
* @param port index CAT524_xxx
* @param data analog value
*/
void cat524Write (uint8_t port, uint8_t data)
{
uint8_t i;
ioSetCAT524Data (FALSE);
ioSetCAT524CS (TRUE);
// Write the start bit.
ioSetCAT524Data (TRUE);
ioSetCAT524Clk (TRUE);
ioSetCAT524Clk (FALSE);
// Set the programming bit.
ioSetCAT524Prog (TRUE);
// Write A0 of the address.
ioSetCAT524Data ((port & 0x01) ? TRUE : FALSE);
ioSetCAT524Clk (TRUE);
ioSetCAT524Clk (FALSE);
// Write A1 of the address.
ioSetCAT524Data ((port & 0x02) ? TRUE : FALSE);
ioSetCAT524Clk (TRUE);
ioSetCAT524Clk (FALSE);
// Write the 8-data bits LSB first.
for (i = 0; i < 8; ++i) {
ioSetCAT524Data ((data & 0x01) ? TRUE : FALSE);
data = data >> 1;
ioSetCAT524Clk (TRUE);
ioSetCAT524Clk (FALSE);
}
ioSetCAT524Data (FALSE);
// Save the data to the CAT524 EEPROM.
for (i = 0 ; i < 4; ++i) {
delay_ms(1);
ioSetCAT524Clk (TRUE);
ioSetCAT524Clk (FALSE);
}
// Clean up.
ioSetCAT524Prog (FALSE);
ioSetCAT524CS (FALSE);
}
/*
* Class to handle the HD44780 LCD controller.
*/
const uint8_t LCD_OFFSET[] = { 0x00, 0x40, 0x14, 0x54 };
#define IO_LCD_BIT0 PIN_B4
#define IO_LCD_BIT1 PIN_B5
#define IO_LCD_BIT2 PIN_B6
#define IO_LCD_BIT3 PIN_B7
#define IO_LCD_RW PIN_B3
#define IO_LCD_E PIN_B2
#define IO_LCD_RS PIN_B1
/**
* Display the <b>character</b> on the LCD.
*
* @param value character to display
*/
void lcdChar (uint8_t value)
{
output_high (IO_LCD_RS);
lcdWrite (value);
}
/**
* Clear the LCD display.
*/
void lcdClear()
{
lcdCommand (0x01);
}
/**
* Send a command to the LCD system.
*/
void lcdCommand (uint8_t command)
{
// Some commands take 1.64mS to complete, so we'll just wait on all of them.
delay_ms (2);
output_low (IO_LCD_RS);
lcdWrite (command);
}
/**
* Move the LCD cursor to the coordinates (x, y) where (1, 1) is
* in the upper left-hand corner.
*
* @param x coordinate
* @param y coordinate
*/
void lcdCursor(uint8_t x, uint8_t y)
{
// Only allow the range (1, 1) to (20, 2)
if (x == 0 || x > 20 || y == 0 || y > 2)
return;
output_low (IO_LCD_RS);
lcdCommand (0x7f + x + LCD_OFFSET[y - 1]);
}
/**
* Initialize the LCD controller and display initial text.
*/
void lcdInit()
{
// Reset the interface.
lcdCommand (0x33);
lcdCommand (0x33);
lcdCommand (0x32);
// Set 4-bit interface mode and display type.
lcdCommand (0x28);
// Enable the display with the cursor off.
lcdCommand (0x0c);
// Clear the display and home the cursor.
lcdCommand (0x01);
// Move the cursor forward with each character.
lcdCommand (0x06);
}
/**
* Display <b>string</b> on the LCD display.
*/
void lcdString(char *string)
{
output_high (IO_LCD_RS);
while (*string != 0)
lcdWrite (*string++);
}
void lcdText (uint8_t x, uint8_t y, char *text)
{
lcdCursor (x, y);
lcdString (text);
}
/**
* Write a byte to the 4-bit interface.
*
* @param data value to write to LCD controller
*/
void lcdWrite (uint8_t data)
{
output_bit (IO_LCD_BIT3, ((data & 0x80) ? 1 : 0));
output_bit (IO_LCD_BIT2, ((data & 0x40) ? 1 : 0));
output_bit (IO_LCD_BIT1, ((data & 0x20) ? 1 : 0));
output_bit (IO_LCD_BIT0, ((data & 0x10) ? 1 : 0));
output_high (IO_LCD_E);
delay_us(1);
output_low (IO_LCD_E);
output_bit (IO_LCD_BIT3, ((data & 0x08) ? 1 : 0));
output_bit (IO_LCD_BIT2, ((data & 0x04) ? 1 : 0));
output_bit (IO_LCD_BIT1, ((data & 0x02) ? 1 : 0));
output_bit (IO_LCD_BIT0, ((data & 0x01) ? 1 : 0));
output_high (IO_LCD_E);
delay_us(1);
output_low (IO_LCD_E);
}
/*
* Class to handle the system operations.
*/
const uint16_t SYS_VERSION = 0x0101;
#define FREQ_LOWER_RANGE 2300
#define FREQ_UPPER_RANGE 2500
// The time in 50mS increments before we save a change in the tuner frequency.
#define SYS_SAVE_FREQ_TIME 300
void sysInit()
{
// Set default outputs before we configure the I/O state.
output_b (0x00);
output_c (0x03);
// Configure the I/O ports direction.
set_tris_b (0x00);
set_tris_c (0x80);
}
/**
* Get the software title and version string.
*
* @param version buffer to write version into
*/
void sysGetVersion (char *version)
{
sprintf (version, "KD7LMO FM-ATV v%d.%d", (uint8_t) (SYS_VERSION >> 8), (uint8_t) (SYS_VERSION & 0xff));
}
enum SYS_OPER_MODE
{
MODE_FREQ,
MODE_BACK_LIGHT,
MODE_BRIGHT,
MODE_CONTRAST,
MODE_COLOR,
MODE_TINT,
MODE_LCD_MODE,
MODE_SYS_INFO
};
void sysGetLCDModeText (uint8_t mode, char *text)
{
switch (mode) {
case 1:
strcpy (text, "Normal - Right");
break;
case 2:
strcpy (text, "Normal - Left ");
break;
case 3:
strcpy (text, "Zoom 2 ");
break;
case 4:
strcpy (text, "Zoom 1 ");
break;
case 5:
strcpy (text, "Stretch 4:3 ");
break;
case 6:
strcpy (text, "Normal 4:3 ");
break;
case 7:
strcpy (text, "Wide 16:9 ");
break;
default:
strcpy (text, "Unknown Mode ");
} // END switch
}
void sysRun()
{
boolean runFlag, ledState, valueChangeFlag;
uint8_t value, lastBusVoltage, lastAGC, versionState, newSetting, ledStateCounter;
uint16_t freq, lastFreqChange;
char buffer[20];
SYS_OPER_MODE operMode;
// Get the last frequency we used.
freq = fileGetFreq();
// Set the tuner and LCD.
tunerSetFreq(freq);
// Configure the state variables.
runFlag = TRUE;
lastBusVoltage = 0xff;
lastAGC = 0;
lastFreqChange = 0;
ledStateCounter = 0;
versionState = 0;
ledState = FALSE;
operMode = MODE_FREQ;
valueChangeFlag = false;
// Display the application version.
guiVersion();
// Display bars on the LCD screen during startup.
while (versionState <= 40) {
if (timerIsUpdated()) {
++versionState;
if (versionState <= 20) {
lcdCursor (versionState, 2);
lcdChar (0x7e);
} else {
lcdCursor (versionState - 20, 2);
lcdChar (' ');
} // END if-else
if (versionState == 40) {
lcdClear();
guiLabel();
guiSetFreq (freq);
} // END if
} // END if
} // END while
//
while (runFlag) {
// Processing that occurs every 50mS.
if (timerIsUpdated()) {
// Read the push buttons.
ioReadPort();
// Save the last frequency to EEPROM if it has changed and the user hasn't moved it recently.
if (lastFreqChange <= SYS_SAVE_FREQ_TIME)
if (++lastFreqChange == SYS_SAVE_FREQ_TIME)
if (freq != fileGetFreq())
fileSetFreq (freq);
// Read the A/D value.
adcUpdate();
// Only update the displayed AGC bar graph if it changed.
switch (operMode) {
case MODE_FREQ:
// Only update the screen if the value changed since the last update.
value = adcGetAGC();
if (value != lastAGC) {
lastAGC = value;
guiSetAGC (value);
} // END if
break;
case MODE_SYS_INFO:
value = adcGetBusVolt();
if (value != lastBusVoltage) {
lastBusVoltage = value;
guiSetBusVoltage (value);
} // END if
break;
} // END switch
// Heartbeat LED.
if (++ledStateCounter == 10) {
ledStateCounter = 0;
ledState = ~ledState;
ioSetLED (ledState);
} // END if
} // END if
// Switch modes based on the select button.
if (ioIsSW1Pushed()) {
// Clear the screen.
lcdClear();
switch (operMode) {
case MODE_FREQ:
operMode = MODE_BACK_LIGHT;
strcpy (buffer, "Back Light Level");
newSetting = fileGetBackLightPWM();
break;
case MODE_BACK_LIGHT:
fileSetBackLightPWM (newSetting);
operMode = MODE_BRIGHT;
strcpy (buffer, "Brightness");
newSetting = fileGetBright();
break;
case MODE_BRIGHT:
fileSetBright (newSetting);
operMode = MODE_CONTRAST;
strcpy (buffer, "Contrast");
newSetting = fileGetContrast();
break;
case MODE_CONTRAST:
fileSetContrast (newSetting);
operMode = MODE_COLOR;
strcpy (buffer, "Chroma (Color)");
newSetting = fileGetColor();
break;
case MODE_COLOR:
fileSetColor (newSetting);
operMode = MODE_TINT;
strcpy (buffer, "Phase (Tint)");
newSetting = fileGetTint();
break;
case MODE_TINT:
fileSetTint (newSetting);
operMode = MODE_LCD_MODE;
strcpy (buffer, "Display Mode");
newSetting = fileGetLCDMode();
break;
case MODE_LCD_MODE:
fileSetLCDMode (newSetting);
operMode = MODE_SYS_INFO;
sysGetVersion (buffer);
break;
case MODE_SYS_INFO:
operMode = MODE_FREQ;
strcpy (buffer, "Freq MHz");
break;
} // END switch
// Display the mode lable on the screen.
lcdText (1, 1, buffer);
// Display the current setting.
switch (operMode) {
case MODE_FREQ:
guiSetFreq (freq);
lastAGC = 0;
strcpy (buffer, "Sig");
lcdText (1, 2, buffer);
break;
case MODE_LCD_MODE:
sysGetLCDModeText (newSetting, buffer);
lcdText (1, 2, buffer);
break;
case MODE_SYS_INFO:
strcpy (buffer, "VDC");
lcdText (6, 2, buffer);
guiSetBusVoltage(adcGetBusVolt());
break;
default:
guiSetBar (newSetting);
break;
} // END switch
} // END if
// Process the switch pushes.
if (ioIsSW2Pushed()) {
valueChangeFlag = true;
switch (operMode) {
case MODE_FREQ:
if (freq < FREQ_UPPER_RANGE) {
lastFreqChange = 0;
++freq;
} // END if
break;
case MODE_LCD_MODE:
if (++newSetting == 8)
newSetting = 1;
sysGetLCDModeText (newSetting, buffer);
lcdText (1, 2, buffer);
break;
case MODE_SYS_INFO:
break;
default:
if (newSetting < 248)
newSetting += 8;
guiSetBar (newSetting);
break;
} // END switch
} // END switch
if (ioIsSW3Pushed()) {
valueChangeFlag = true;
switch (operMode) {
case MODE_FREQ:
if (freq > FREQ_LOWER_RANGE) {
lastFreqChange = 0;
--freq;
} // END if
break;
case MODE_LCD_MODE:
if (--newSetting == 0)
newSetting = 7;
sysGetLCDModeText (newSetting, buffer);
lcdText (1, 2, buffer);
break;
case MODE_SYS_INFO:
break;
default:
if (newSetting > 0)
newSetting -= 8;
guiSetBar (newSetting);
break;
} // END switch
} // END if
if (valueChangeFlag) {
valueChangeFlag = false;
switch (operMode) {
case MODE_FREQ:
sysSetFreq (freq);
break;
case MODE_BACK_LIGHT:
set_pwm1_duty (newSetting);
break;
case MODE_BRIGHT:
cat524Write (CAT524_BRIGHT, newSetting);
break;
case MODE_CONTRAST:
cat524Write (CAT524_CONT, newSetting);
break;
case MODE_COLOR:
cat524Write (CAT524_COLOR, newSetting);
break;
case MODE_TINT:
cat524Write (CAT524_TINT, newSetting);
break;
case MODE_LCD_MODE:
ioSetMode (newSetting);
break;
} // END switch
} // END if
} // END while
}
/**
* Set the receiver frequency and display it.
*
* @param freq in MHz
*/
void sysSetFreq (uint16_t freq)
{
guiSetFreq(freq);
tunerSetFreq (freq);
}
/*
* Class to handle the timer functions.
*/
uint8_t timerInterruptCount;
uint16_t timerCompare;
boolean timerUpdateFlag, timerPWM;
// The number of CCP_2 timer clicks in a 5mS time slice.
// (ClockRate / 4) / (T1_DIV_BY_x) * 576) => (14745600 / 4) / (8 * 2304) = 5mS
#define TIMER_RATE 576
void timerInit()
{
// Setup the counters that are used in the timerInterrupt function.
timerInterruptCount = 0;
timerUpdateFlag = FALSE;
timerPWM = FALSE;
// Configure CCP2 to interrupt at 5mS rate.
timerCompare = TIMER_RATE;
CCP_2 = timerCompare;
set_timer1(0);
setup_ccp2( CCP_COMPARE_INT );
setup_timer_1( T1_INTERNAL | T1_DIV_BY_8 );
// Setup CCP1 to generate PWM pulses at 275Hz.
setup_ccp1(CCP_PWM);
set_timer2(0);
setup_timer_2(T2_DIV_BY_16, 209, 1);
set_pwm1_duty(fileGetBackLightPWM());
// Setup our interrupts.
enable_interrupts(GLOBAL);
enable_interrupts(INT_CCP2);
}
// This ISR is called when the timer register matches the compare register.
// The interrupt rate is programmed to 5mS.
#INT_CCP2
void timerInterrupt()
{
// Setup for the next interrupt.
timerCompare += TIMER_RATE;
CCP_2 = timerCompare;
// Set a processing flag every 50mS.
if (++timerInterruptCount == 10) {
timerInterruptCount = 0;
timerUpdateFlag = TRUE;
} // END if
}
/**
* Returns a flag that is set true every 50mS. The method automatically resets to false after
* it returns true.
*
* @return true if 50mS has passed; otherwise false
*/
boolean timerIsUpdated()
{
if (timerUpdateFlag) {
timerUpdateFlag = FALSE;
return true;
} // END if
return false;
}
/*
* Class to handle the 2.4GHz tuner PLL. The tuner utilizes the Mitel SA5055 2.6GHz
* synthesizer.
*/
/**
* Determine if the tuner PLL is locked
*
* @return true if locked; otherwise false
*/
boolean tunerIsLocked()
{
uint8_t returnCode;
// Get the PLL controller status byte.
i2c_start();
i2c_write(0xc3);
returnCode = i2c_read();
i2c_stop();
// Bit 6 is the PLL locked flag.
if ((returnCode & 0x40) == 0x40)
return TRUE;
else
return FALSE;
}
/**
* Set the receiver frequency. The IF is 479.5MHz so we set the frequency lower than the
* desired receive frequency. The frequency is based on a 4MHz reference divided by 512.
*
* @param freq in MHz
*/
void tunerSetFreq(uint16_t freq)
{
// Tell the I2C device to connect
i2c_start();
// Address the SA5055 PLL.
i2c_write(0xc2);
// Calculate the receive frequency minus the IF frequency of 479.5 MHz (3836 = 497.5 * 8)
freq = (8 * freq) - 3836;
// Write the divider value.
i2c_write(freq >> 8);
i2c_write(freq & 0xff);
i2c_write(0xce);
i2c_write(0x00);
i2c_stop();
}
/*
* Class to handle the video functions.
*/
/**
* Setup the video controller.
*/
void videoInit()
{
cat524Write (CAT524_COLOR, fileGetColor());
cat524Write (CAT524_BRIGHT, fileGetBright());
cat524Write (CAT524_CONT, fileGetContrast());
cat524Write (CAT524_TINT, fileGetTint());
ioScanDown (TRUE);
ioCompVideo (TRUE);
ioSetMode (fileGetLCDMode());
}
// This is where we go after reset.
void main()
{
// Initialize the base system.
sysInit();
// Wait for the hardware to come up after reset.
delay_ms (100);
// If the file system is not valid, then set default values.
if (!fileInit()) {
fileSetFreq (2418);
fileSetBackLightPWM (0x80);
fileSetColor (0x80);
fileSetBright (0x80);
fileSetContrast (0x80);
fileSetTint (0x80);
fileSetLCDMode (0x06);
} // END if
// Initialize the subsystems.
adcInit();
ioInit();
lcdInit();
timerInit();
videoInit();
// Now run the system.
sysRun();
}