Files
HendiControlFirmware/Control/firmware/HendiCtrl/main.c
T
jens 2e57afa19a - refactored variables
git-svn-id: http://moon:8086/svn/projects/HendiControl@176 fda53097-d464-4ada-af97-ba876c37ca34
2019-03-30 13:29:55 +00:00

422 lines
9.1 KiB
C
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 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 = 0;
int g_switch_in_last = 0;
// 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,
StateError = 2,
State_NumStates
} State_t;
static const char SW_IDENTIFIER[] = "Hendi-Control";
static const char SW_VERSION[] = "v1.1";
static const char *state_str[State_NumStates] = {"Normal","Remote","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 = StateNormal;
State_t state_next = StateNormal;
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);
setSwitch(1);
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);
}
}
}
// 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);
}
}
}
// Enter/exit remote
else if (toupper(*pArgs) == 'R')
{
pArgs++;
if (!isdigit(*pArgs))
{
break;
}
uint16_t arg = (uint16_t)strtol(pArgs, &pArgs, 10);
if (arg == 1)
{
// Enter remote
if (state == StateNormal)
{
setPower(PowerLow);
setSwitch(SwitchOff);
state_next = StateRemote;
PRINT_ANSWER("OK");
}
}
else if (arg == 0)
{
// Exit remote
if (state == StateRemote)
{
setPower(PowerLow);
setSwitch(SwitchOff);
state_next = StateNormal;
PRINT_ANSWER("OK");
}
}
}
// Debug Control
else if (toupper(*pArgs) == 'D')
{
pArgs++;
if (!isdigit(*pArgs))
{
break;
}
g_debug = (uint16_t)strtol(pArgs, &pArgs, 10);
PRINT_ANSWER("OK");
}
// 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++;
}
} // 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)
{
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;
}
}