/* * uart_echo.c * * Created: 16.08.2018 17:39:49 * Author : jens */ #include #include #include #include #include #include #include #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) static const uint16_t POTI_HSYTERSE = 1; int16_t adc_poti = 0; int16_t adc_swin = 0; int sw_in_last = 0; size_t cmdStrSize = 0; Fifo messageFifo; uint16_t g_power = 0; int g_debug = 0; int g_switch = 0; static const char SW_IDENTIFIER[] = "Hendi-Control"; static const char SW_VERSION[] = "v1.1"; FILE uart_file = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); typedef enum _eSwitch { SwitchOff = 0, SwitchOn = 1 } Switch; void setSwitch(int on) { g_switch = 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 power) { g_power = power; PRINT_DEBUG("Set Power to %u\n", power); uint8_t dac_cmd[] = {0x00, 0x00}; // 6.2 Write Volatile Memory (C2:C0 = ‘010’) size_t res = MCP47x6_write_volatile_dac(power, dac_cmd, sizeof(dac_cmd)); i2c_send(0x60, I2C_WRITE, dac_cmd, res); } typedef enum _eState_t { StateNormal = 0, StateRemote = 1, StateError = 2, State_NumStates } State_t; int main(void) { int hb_state = 0; cli(); wdt_reset(); wdt_disable(); const char *state_str[State_NumStates] = {"Normal","Remote","Error"}; 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) == '?') { PRINT_ANSWER("%04u", g_power); pArgs++; } else { if (!isdigit(*pArgs)) { break; } uint16_t arg = (uint16_t)strtol(pArgs, &pArgs, 10); if (state == StateRemote) { setPower(arg); } } } // Switch Control else if (toupper(*pArgs) == 'S') { pArgs++; if ((*pArgs) == '?') { PRINT_ANSWER("%u", g_switch); pArgs++; } else { if (!isdigit(*pArgs)) { break; } uint16_t arg = (uint16_t)strtol(pArgs, &pArgs, 10); if (state == StateRemote) { setSwitch(arg); } } } // Enter remote else if (toupper(*pArgs) == 'R') { pArgs++; if (state == StateNormal) { setPower(PowerLow); setSwitch(SwitchOff); state_next = StateRemote; } } // Exit remote else if (toupper(*pArgs) == 'X') { pArgs++; if (state == StateRemote) { setPower(PowerLow); setSwitch(SwitchOff); state_next = StateNormal; } } // Debug Control else if (toupper(*pArgs) == 'D') { pArgs++; if (!isdigit(*pArgs)) { break; } g_debug = (uint16_t)strtol(pArgs, &pArgs, 10); } // SW identifier else if (toupper(*pArgs) == 'I') { pArgs++; PRINT_ANSWER("%s", SW_IDENTIFIER); } // Version else if (toupper(*pArgs) == 'V') { pArgs++; PRINT_ANSWER("%s", SW_VERSION); } // 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 - adc_poti) <= -(int16_t)POTI_HSYTERSE) || ((adc_curr - adc_poti) >= (int16_t)POTI_HSYTERSE)) { if (state == StateNormal) { setPower(adc_curr << 2); } adc_poti = adc_curr; } } if (adc_ch == 2) { adc_swin = adc_curr; } } 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)); int sw_in = adc_swin > 512; if (sw_in != sw_in_last) { PRINT_DEBUG ("PwrSwitch_in = %d\n", sw_in); if (sw_in == 0) { if (state == StateError || state == StateRemote) { setSwitch(SwitchOn); state_next = StateNormal; } } } sw_in_last = sw_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; } }