Topic: tech dcc pc src prev next
tech dcc pc src > controller.c
#include "controller.h"
#include <util/delay.h>
#include "dcc.h"
#include "lcd.h"
#include "menu.h"
#include "pins.h"
#include "wdt.h"
unsigned char pot_to_speed(adc_type pot, bool steps_128)
{
return (unsigned char)(
steps_128 ?
(unsigned char)((pot / 8 > 126) ? 126 : (pot / 8)) :
(unsigned char)((pot / 32 > 28) ? 28 : (pot / 32))
);
}
void transmit_speed(
const cfg_loco *loco,
unsigned char speed,
bool direction
)
{
switch(loco->speed_steps)
{
case SPEED_STEPS_128:
DCC_Transmit(Packet_CreateSpeed128(loco->address, direction, speed));
break;
case SPEED_STEPS_28:
DCC_Transmit(Packet_CreateSpeed28(loco->address, direction, speed));
break;
}
}
void Controller_CheckOverCurrent(adc_type current)
{
if(current > HERMES_CURRENT_LIMIT)
{
DCC_Stop();
_delay_ms(100);
LCD_ReInit();
Menu_Notice("Short");
Wdt_Reset();
}
}
unsigned char Controller_FunctionMenu(
const cfg_loco *loco,
functions_type *function_state
)
{
if(loco->f_enable == 0)
return CFG_NULL_INDEX;
typedef struct
{
const cfg_loco *loco;
functions_type *function_state;
unsigned char index;
unsigned char selected;
} state;
state context = {
.loco = loco,
.function_state = function_state,
.index = 0,
.selected = CFG_NULL_INDEX
};
// Get the currently selected function number.
unsigned char selected_function(const state *context_)
{
unsigned char index = (unsigned char)(context_->index + 1);
functions_type f = context_->loco->f_enable;
for(unsigned char i = 0; i < 32; ++i)
{
if(f & 1)
--index;
if(index == 0)
return (unsigned char)i;
f >>= 1;
}
return 0;
}
// Get the state of the currently selected function.
bool selected_function_state(const state *context_)
{
unsigned char f_no = selected_function(context_);
return (*context_->function_state >> f_no) & 1;
}
void button(void *v, const switch_type sw)
{
state *context_ = (state*)v;
if(HERMES_SWITCH_NO(sw) == HERMES_SWITCH_BACK)
Menu_Finish();
if(HERMES_SWITCH_NO(sw) == HERMES_RE_SEL)
{
context_->selected = selected_function(context_);
Menu_Finish();
}
// The rotary encoder moves through the list.
if(HERMES_SWITCH_NO(sw) == HERMES_RE_ACW)
{
context_->index = (unsigned char)(
(Cfg_LocoFunctions(context_->loco) + context_->index - 1) %
Cfg_LocoFunctions(context_->loco)
);
Menu_Redraw();
}
if(HERMES_SWITCH_NO(sw) == HERMES_RE_CW)
{
context_->index = (unsigned char)(
(context_->index + 1) % Cfg_LocoFunctions(context_->loco)
);
Menu_Redraw();
}
if(HERMES_SWITCH_NO(sw) == HERMES_RE_SEL)
{
unsigned char f_no = selected_function(context_);
context_->selected = f_no;
/*if((context_->loco->f_momentary >> f_no) & 1)*/
/*{*/
/*// Transmit on/off.*/
/*Controller_TransmitFunctionGroup(*/
/*context_->operations->loco.address,*/
/**context_->function_state | (1UL << f_no),*/
/*Controller_FunctionGroup(f_no),*/
/*HERMES_MOMENTARY_FUNCTION_ACTIVATION_COUNT*/
/*);*/
/*Controller_TransmitFunctionGroup(*/
/*context_->operations->loco.address,*/
/**context_->function_state,*/
/*Controller_FunctionGroup(f_no),*/
/*HERMES_MOMENTARY_FUNCTION_DEACTIVATION_COUNT*/
/*);*/
/*}*/
/*else*/
/*{*/
/*if((*context_->function_state >> f_no) & 1)*/
/*{*/
/*// Transmit 'off'.*/
/**context_->function_state = *context_->function_state & ~(1UL << f_no);*/
/*}*/
/*else*/
/*{*/
/*// Transmit 'on'.*/
/**context_->function_state = *context_->function_state | (1UL << f_no);*/
/*}*/
/*}*/
}
}
void draw(void *v)
{
state *context_ = (state*)v;
LCD_DefineHermesChars(HERMES_LCD_CUSTOM_MODE_MENU);
unsigned char f_no = selected_function(context_);
LCD_Clear();
LCD_PutS("Fn. ");
// Function numbers can only have one or two digits.
if(f_no < 10)
LCD_PutC(' ');
LCD_PutI(f_no);
LCD_PutS(
((context_->loco->f_momentary >> f_no) & 1) ?
" (once)" :
(selected_function_state(context_) ? " (ON)" : " (OFF)")
);
LCD_Move(0, 1);
LCD_PutC(HERMES_LCD_CHAR_UP);
LCD_PutS(" ");
LCD_PutC(HERMES_LCD_CHAR_ACW);
LCD_PutS(" ");
LCD_PutC(HERMES_LCD_CHAR_CW);
}
Menu_EventLoop(button, draw, 0, &context);
return context.selected;
}
cfg_address_type Controller_AccessoryMenu(cfg_address_type *on_accessories)
{
typedef struct
{
// List of all accessories.
cfg_address_type accessory[CFG_ACCESSORY_LIST_LENGTH + 1];
// Index into 'accessory'.
int accessory_index;
// Selected accessory.
cfg_address_type selected;
// List of accessories in the 'on' state.
cfg_address_type *on_accessories;
} state;
state context = {
.accessory_index = 0,
.selected = CFG_NULL_ADDR,
.on_accessories = on_accessories
};
Cfg_Accessories(context.accessory);
// Don't bother to list accessories if the accessory list is empty.
if(context.accessory[0] == CFG_NULL_ADDR)
return CFG_NULL_ADDR;
void draw(void *v)
{
state *context_ = (state*)v;
LCD_DefineHermesChars(HERMES_LCD_CUSTOM_MODE_MENU);
LCD_Clear();
cfg_address_type accessory_address = context_->accessory[context_->accessory_index];
const bool accessory_state = (
Cfg_IndexInList(accessory_address, context_->on_accessories) !=
CFG_NULL_INDEX
);
LCD_PutS("Ac. ");
LCD_PutI((int)accessory_address);
LCD_Move(8, 0);
LCD_PutS(
accessory_state ?
"(ON)" : "(OFF)"
);
LCD_Move(0, 1);
LCD_PutC(HERMES_LCD_CHAR_UP);
LCD_PutS(" ");
LCD_PutC(HERMES_LCD_CHAR_ACW);
LCD_PutS(" ");
LCD_PutC(HERMES_LCD_CHAR_CW);
LCD_PutS(" ");
LCD_PutC(HERMES_LCD_CHAR_OK);
}
void button(void *v, switch_type sw)
{
state *context_ = (state*)v;
if(HERMES_SWITCH_NO(sw) == HERMES_SWITCH_BACK)
Menu_Finish();
if(HERMES_SWITCH_NO(sw) == HERMES_RE_SEL)
{
context_->selected =
context_->accessory[context_->accessory_index];
Menu_Finish();
}
if(HERMES_SWITCH_NO(sw) == HERMES_RE_ACW)
{
context_->accessory_index =
(Cfg_AddressCount(context_->accessory) + context_->accessory_index - 1) %
Cfg_AddressCount(context_->accessory);
Menu_Redraw();
}
if(HERMES_SWITCH_NO(sw) == HERMES_RE_CW)
{
context_->accessory_index =
(context_->accessory_index + 1) %
Cfg_AddressCount(context_->accessory);
Menu_Redraw();
}
}
Menu_EventLoop(button, draw, 0, &context);
return context.selected;
}
unsigned char Controller_FunctionGroup(unsigned char function_no)
{
if(function_no < 5)
return 1;
else if(function_no < 9)
return 2;
else if(function_no < 13)
return 3;
else if(function_no < 21)
return 4;
else if(function_no < 29)
return 5;
return 6;
}
void Controller_TransmitFunctionGroup(
cfg_address_type address,
functions_type function_state,
unsigned char group,
unsigned char repeats
)
{
switch(group)
{
case 1:
DCC_TransmitRepeat(
Packet_CreateFunction0_4(
address,
(function_state & 0b11111)
),
repeats
);
break;
case 2:
DCC_TransmitRepeat(
Packet_CreateFunction5_8(
address,
((function_state >> 5) & 0b1111)
),
repeats
);
break;
case 3:
DCC_TransmitRepeat(
Packet_CreateFunction9_12(
address,
((function_state >> 9) & 0b1111)
),
repeats
);
break;
case 4:
DCC_TransmitRepeat(
Packet_CreateFunction13_20(
address,
((function_state >> 13) & 0b11111111)
),
repeats
);
break;
case 5:
DCC_TransmitRepeat(
Packet_CreateFunction21_28(
address,
((function_state >> 21) & 0b11111111)
),
repeats
);
break;
}
}