- needed to modify init values of variables - switch is off on start up git-svn-id: http://moon:8086/svn/projects/HendiControl@184 fda53097-d464-4ada-af97-ba876c37ca34
455 lines
10 KiB
C
Executable File
455 lines
10 KiB
C
Executable File
/*
|
||
* uart_echo.c
|
||
*
|
||
* Created: 16.08.2018 17:39:49
|
||
* Author : jens
|
||
*/
|
||
|
||
#include <ctype.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <avr/io.h>
|
||
#include <avr/wdt.h>
|
||
#include <avr/interrupt.h>
|
||
|
||
#include "machine.h"
|
||
#include "fifo.h"
|
||
#include "message.h"
|
||
#include "adc.h"
|
||
#include "port.h"
|
||
#include "timer.h"
|
||
#include "uart.h"
|
||
#include "i2c.h"
|
||
#include "mcp42x6.h"
|
||
|
||
#define PRINT(a,...) printf(a, ##__VA_ARGS__)
|
||
#define PRINT_DEBUG(a,...) \
|
||
if (g_debug) \
|
||
{ \
|
||
printf(a, ##__VA_ARGS__); \
|
||
}
|
||
|
||
#define PRINT_CRLF putchar(0x0D);putchar(0x0A);
|
||
#define PRINT_ANSWER(a,...) PRINT_CRLF; printf(a, ##__VA_ARGS__);
|
||
#define PRINT_PROMPT PRINT_CRLF; putchar(':');
|
||
#define USART_BAUDRATE (115200UL)
|
||
#define TIMER_HW_CLOCK (F_CPU/8)
|
||
#define TIMER_IRQ_CLOCK 1000UL
|
||
#define TIMER_HW_RELOAD (0xFFFF-(TIMER_HW_CLOCK/TIMER_IRQ_CLOCK))
|
||
|
||
#define TIMER_SW_DELAY_MS(dly) ((dly*TIMER_IRQ_CLOCK)/1000UL)
|
||
|
||
FILE uart_file = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
|
||
|
||
size_t cmdStrSize = 0;
|
||
Fifo messageFifo;
|
||
int g_debug = 0;
|
||
|
||
// Switch IN
|
||
int16_t g_switch_in_digits = 0;
|
||
int g_switch_in = 0xFFFF;
|
||
int g_switch_in_last = 0xFFFF;
|
||
|
||
// Switch OUT
|
||
int g_switch_out = 0;
|
||
|
||
// Poti IN
|
||
uint16_t g_poti_in_digits = 0;
|
||
|
||
// Poti OUT
|
||
uint16_t g_poti_out_digits = 0;
|
||
|
||
typedef enum _eState_t
|
||
{
|
||
StateNormal = 0,
|
||
StateRemote = 1,
|
||
StateSuspend = 2,
|
||
StateError = 3,
|
||
State_NumStates
|
||
} State_t;
|
||
|
||
static const char SW_IDENTIFIER[] = "Hendi-Control";
|
||
static const char SW_VERSION[] = "v1.12";
|
||
static const char *state_str[State_NumStates] = {"Normal", "Remote", "Suspend", "Error"};
|
||
static const uint16_t POTI_HSYTERSE = 1;
|
||
|
||
typedef enum _eSwitch
|
||
{
|
||
SwitchOff = 0,
|
||
SwitchOn = 1
|
||
} Switch;
|
||
|
||
void setSwitch(int on)
|
||
{
|
||
g_switch_out = on;
|
||
const char *sw_str[2] = {"OFF", "ON"};
|
||
PRINT_DEBUG("Set switch to %s\n", sw_str[on != 0]);
|
||
portSet(PwrSwitch_out, on != 0);
|
||
}
|
||
|
||
typedef enum _ePower
|
||
{
|
||
PowerLow = 4095,
|
||
PowerMax = 0
|
||
} Power;
|
||
|
||
void setPower(uint16_t digits)
|
||
{
|
||
g_poti_out_digits = digits;
|
||
PRINT_DEBUG("Set Power to %u digits\n", digits);
|
||
uint8_t dac_cmd[] = {0x00, 0x00}; // 6.2 Write Volatile Memory (C2:C0 = ‘010’)
|
||
size_t res = MCP47x6_write_volatile_dac(digits, dac_cmd, sizeof(dac_cmd));
|
||
i2c_send(0x60, I2C_WRITE, dac_cmd, res);
|
||
}
|
||
|
||
int main(void)
|
||
{
|
||
int hb_state = 0;
|
||
cli();
|
||
wdt_reset();
|
||
wdt_disable();
|
||
|
||
State_t state = StateSuspend;
|
||
State_t state_next = StateSuspend;
|
||
|
||
fifo_init(&messageFifo, 8, sizeof(Msg_t), "Fifo");
|
||
|
||
/* Replace with your application code */
|
||
uart_init(&messageFifo, USART_BAUDRATE);
|
||
timer_init(&messageFifo, TIMER_HW_RELOAD, TimerClockSel_PS_8);
|
||
adc_init(&messageFifo);
|
||
i2c_init();
|
||
port_init();
|
||
|
||
stdout = &uart_file;
|
||
printf("%s %s\n", SW_IDENTIFIER, SW_VERSION);
|
||
|
||
uint8_t dac_cmd[] = {0x00, 0x00, 0x00}; // 6.1 Write Volatile DAC Register (C2:C0 = ‘00x’)
|
||
size_t res = MCP47x6_write_volatile_mem(0x0000, dac_cmd, sizeof(dac_cmd));
|
||
i2c_send(0x60, I2C_WRITE, dac_cmd, res);
|
||
|
||
char cmdStr[16];
|
||
PRINT_PROMPT;
|
||
|
||
// Start Timer
|
||
timer_start(TIMER_GENERAL, 0);
|
||
timer_start(TIMER_ADC, 0);
|
||
|
||
sei();
|
||
while (1)
|
||
{
|
||
state_next = state;
|
||
Msg_t msg;
|
||
if (!fifo_isEmpty(&messageFifo))
|
||
{
|
||
fifo_pop(&messageFifo, &msg);
|
||
switch(msg.code)
|
||
{
|
||
case Uart:
|
||
{
|
||
// Process Uart message
|
||
char c = (char)msg.m.uart.data;
|
||
cmdStr[cmdStrSize] = 0;
|
||
|
||
// Command finished with CR/LF
|
||
if (c == 0x0D)
|
||
{
|
||
char *pArgs = cmdStr;
|
||
cmdStrSize = 0;
|
||
while (*pArgs)
|
||
{
|
||
// Power Control
|
||
if (toupper(*pArgs) == 'P')
|
||
{
|
||
pArgs++;
|
||
if ((*pArgs) == '?')
|
||
{
|
||
pArgs++;
|
||
PRINT_ANSWER("OK:%04u", g_poti_out_digits);
|
||
}
|
||
else
|
||
{
|
||
if (!isdigit(*pArgs))
|
||
{
|
||
break;
|
||
}
|
||
uint16_t arg = (uint16_t)strtol(pArgs, &pArgs, 10);
|
||
if (state == StateRemote)
|
||
{
|
||
setPower(arg);
|
||
PRINT_ANSWER("OK:%04u", g_poti_out_digits);
|
||
}
|
||
else
|
||
{
|
||
PRINT_ANSWER("ERR:Invalid state");
|
||
}
|
||
}
|
||
}
|
||
|
||
// Switch Control
|
||
else if (toupper(*pArgs) == 'S')
|
||
{
|
||
pArgs++;
|
||
if ((*pArgs) == '?')
|
||
{
|
||
pArgs++;
|
||
PRINT_ANSWER("OK:%u", g_switch_out);
|
||
}
|
||
else
|
||
{
|
||
if (!isdigit(*pArgs))
|
||
{
|
||
break;
|
||
}
|
||
uint16_t arg = (uint16_t)strtol(pArgs, &pArgs, 10);
|
||
|
||
if (state == StateRemote)
|
||
{
|
||
setSwitch(arg);
|
||
PRINT_ANSWER("OK:%u", g_switch_out);
|
||
}
|
||
else
|
||
{
|
||
PRINT_ANSWER("ERR:Invalid state");
|
||
}
|
||
}
|
||
}
|
||
|
||
// Enter/exit remote
|
||
else if (toupper(*pArgs) == 'R')
|
||
{
|
||
pArgs++;
|
||
if ((*pArgs) == '?')
|
||
{
|
||
pArgs++;
|
||
PRINT_ANSWER("OK:%d", (int)(state_next == StateRemote));
|
||
}
|
||
else
|
||
{
|
||
if (!isdigit(*pArgs))
|
||
{
|
||
break;
|
||
}
|
||
uint16_t arg = (uint16_t)strtol(pArgs, &pArgs, 10);
|
||
if (arg == 1)
|
||
{
|
||
// Enter remote
|
||
if (state == StateNormal || state == StateSuspend)
|
||
{
|
||
setPower(PowerLow);
|
||
setSwitch(SwitchOff);
|
||
state_next = StateRemote;
|
||
PRINT_ANSWER("OK:%d", arg);
|
||
}
|
||
else
|
||
{
|
||
PRINT_ANSWER("ERR:Invalid state");
|
||
}
|
||
}
|
||
else if (arg == 0)
|
||
{
|
||
// Exit remote
|
||
if (state == StateRemote)
|
||
{
|
||
setPower(PowerLow);
|
||
setSwitch(SwitchOff);
|
||
state_next = StateSuspend;
|
||
PRINT_ANSWER("OK:%d", arg);
|
||
}
|
||
else
|
||
{
|
||
PRINT_ANSWER("ERR:Invalid state");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Debug Control
|
||
else if (toupper(*pArgs) == 'D')
|
||
{
|
||
pArgs++;
|
||
if ((*pArgs) == '?')
|
||
{
|
||
pArgs++;
|
||
PRINT_ANSWER("OK:%d", (int)(state_next == StateRemote));
|
||
}
|
||
else
|
||
{
|
||
if (!isdigit(*pArgs))
|
||
{
|
||
break;
|
||
}
|
||
g_debug = (uint16_t)strtol(pArgs, &pArgs, 10);
|
||
PRINT_ANSWER("OK:%d", g_debug);
|
||
}
|
||
}
|
||
|
||
// SW identifier
|
||
else if (toupper(*pArgs) == 'I')
|
||
{
|
||
pArgs++;
|
||
if ((*pArgs) == '?')
|
||
{
|
||
pArgs++;
|
||
PRINT_ANSWER("OK:%s", SW_IDENTIFIER);
|
||
}
|
||
}
|
||
|
||
// Version
|
||
else if (toupper(*pArgs) == 'V')
|
||
{
|
||
pArgs++;
|
||
if ((*pArgs) == '?')
|
||
{
|
||
pArgs++;
|
||
PRINT_ANSWER("OK:%s", SW_VERSION);
|
||
}
|
||
}
|
||
|
||
// State
|
||
else if (toupper(*pArgs) == 'T')
|
||
{
|
||
pArgs++;
|
||
if ((*pArgs) == '?')
|
||
{
|
||
pArgs++;
|
||
const char *pState = state_str[state];
|
||
PRINT_ANSWER("OK:%s", pState);
|
||
}
|
||
}
|
||
|
||
// no match
|
||
else
|
||
{
|
||
pArgs++;
|
||
PRINT_ANSWER("ERR:Unknown command");
|
||
}
|
||
|
||
} // while (*pArgs)
|
||
timer_start(TIMER_TIMEOUT, TIMER_SW_DELAY_MS(10000));
|
||
PRINT_PROMPT;
|
||
}
|
||
else
|
||
{
|
||
if ((c != 0x0A) && (c != 0x0D))
|
||
{
|
||
if (cmdStrSize < (sizeof(cmdStr)-1))
|
||
{
|
||
cmdStr[cmdStrSize++] = c;
|
||
}
|
||
putchar(c);
|
||
}
|
||
} // if (c == 0x0D)
|
||
} // case Uart:
|
||
break;
|
||
|
||
case AdcComplete:
|
||
{
|
||
uint8_t adc_ch = msg.m.adc.ch;
|
||
int16_t adc_curr = (int16_t)msg.m.adc.data;
|
||
if (adc_ch == 0)
|
||
{
|
||
if (((adc_curr - (int16_t)g_poti_in_digits) <= -(int16_t)POTI_HSYTERSE) || ((adc_curr - (int16_t)g_poti_in_digits) >= (int16_t)POTI_HSYTERSE))
|
||
{
|
||
if (state == StateNormal)
|
||
{
|
||
setPower(adc_curr << 2);
|
||
}
|
||
g_poti_in_digits = (uint16_t)adc_curr;
|
||
}
|
||
}
|
||
if (adc_ch == 2)
|
||
{
|
||
g_switch_in_digits = adc_curr;
|
||
g_switch_in = (int)(g_switch_in_digits > 512);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case Timer:
|
||
{
|
||
int timer_id = msg.m.timer.ch;
|
||
switch(timer_id)
|
||
{
|
||
case TIMER_GENERAL:
|
||
{
|
||
uint16_t interval = 1000;
|
||
uint16_t pulse = 50;
|
||
if (state == StateRemote)
|
||
{
|
||
interval = 500;
|
||
pulse = 50;
|
||
}
|
||
|
||
hb_state = !hb_state;
|
||
if (hb_state)
|
||
{
|
||
timer_start(timer_id, TIMER_SW_DELAY_MS(pulse));
|
||
}
|
||
else
|
||
{
|
||
timer_start(timer_id, TIMER_SW_DELAY_MS((interval-pulse)));
|
||
}
|
||
portSet(Led_HB, hb_state);
|
||
}
|
||
break;
|
||
|
||
case TIMER_TIMEOUT:
|
||
{
|
||
if (state == StateRemote)
|
||
{
|
||
PRINT_DEBUG("Remote timeout!\n");
|
||
state_next = StateError;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TIMER_ADC:
|
||
{
|
||
timer_start(timer_id, TIMER_SW_DELAY_MS(50));
|
||
if (g_switch_in != g_switch_in_last)
|
||
{
|
||
PRINT_DEBUG ("PwrSwitch_in = %d\n", g_switch_in);
|
||
if (g_switch_in == 0)
|
||
{
|
||
if (state == StateError || state == StateRemote || state == StateSuspend)
|
||
{
|
||
setSwitch(SwitchOn);
|
||
state_next = StateNormal;
|
||
}
|
||
}
|
||
}
|
||
g_switch_in_last = g_switch_in;
|
||
adc_enqueue_conversion(0);
|
||
adc_enqueue_conversion(2);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case NOP:
|
||
break;
|
||
}
|
||
}
|
||
if (state != state_next)
|
||
{
|
||
PRINT_DEBUG("State change \"%s\" => \"%s\"\n", state_str[state], state_str[state_next]);
|
||
if (state_next == StateError)
|
||
{
|
||
setPower(PowerLow);
|
||
setSwitch(SwitchOff);
|
||
portSet(Led_ERR, 1);
|
||
}
|
||
if (state_next == StateNormal)
|
||
{
|
||
portSet(Led_ERR, 0);
|
||
}
|
||
}
|
||
state = state_next;
|
||
|
||
}
|
||
}
|
||
|