mirror of
https://github.com/eddyem/IR-controller.git
synced 2025-12-06 10:45:15 +03:00
428 lines
13 KiB
C
428 lines
13 KiB
C
/*
|
|
* powerhw.c - functions to work with other power loads (shutter, heaters and so on)
|
|
*
|
|
* Copyright 2015 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
|
|
*
|
|
* 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., 51 Franklin Street, Fifth Floor, Boston,
|
|
* MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "main.h"
|
|
// state of shutter - global variable to omit interface functions
|
|
shutter_state Shutter_State = SHUTTER_NOTREADY;
|
|
int8_t manual_pin_old_state = -1;
|
|
int8_t camera_pin_old_state = -1;
|
|
//uint8_t changed_manually = 0; // ==1 if shutter state was changed by manual switch
|
|
|
|
// function to be runned from timer irq
|
|
//void (*shutter_timer_fn)() = NULL;
|
|
|
|
#define DWT_CYCCNT *(volatile uint32_t *)0xE0001004
|
|
#define DWT_CONTROL *(volatile uint32_t *)0xE0001000
|
|
#define SCB_DEMCR *(volatile uint32_t *)0xE000EDFC
|
|
|
|
/**
|
|
* Make blocking pause in 'us' microsecond, after which run function fn_ready
|
|
* @param us - pause in microseconds
|
|
* @param fn_ready - function to run at end of pause
|
|
* @param block - == 0 if calling is non-blocking, otherwice == 1
|
|
*/
|
|
void shutter_wait_block(uint32_t us, void(*fn_ready)()){
|
|
/*
|
|
if(!fn_ready) return;
|
|
//DBG("wait for previous .. ");
|
|
while(shutter_timer_fn); // wait for ending of previous operation
|
|
//DBG("ok\n");
|
|
shutter_timer_fn = fn_ready;
|
|
timer_set_period(SHUTTER_TIM, us);
|
|
timer_enable_counter(SHUTTER_TIM);
|
|
*/
|
|
if(!fn_ready) return;
|
|
//int i;
|
|
us *= 72;
|
|
// wait for us*72 cycles
|
|
SCB_DEMCR |= 0x01000000;
|
|
DWT_CYCCNT = 0;
|
|
DWT_CONTROL|= 1;
|
|
// for (i = 0; i < us; i++) __asm__("nop");
|
|
while(DWT_CYCCNT < us);
|
|
fn_ready();
|
|
}
|
|
|
|
/**
|
|
* Make nonblocking pause in 'ms' millisecond, after which we should run function fn_ready
|
|
* run it with us == 0 and/or fn_ready == 0 to check old pause
|
|
*/
|
|
void shutter_wait_nonblock(uint32_t ms, void(*fn_ready)()){
|
|
static uint8_t waiting_for = 0; // == 1 if we are waiting for something
|
|
static uint32_t wait_till = 0; // time counter for waiting
|
|
static void(*fn_ready_saved)() = NULL;
|
|
if(ms == 0 || fn_ready == 0){ // check
|
|
if(waiting_for && Timer >= wait_till){ // it's time
|
|
waiting_for = 0;
|
|
if(fn_ready_saved){
|
|
void(*f)() = fn_ready_saved;
|
|
fn_ready_saved = NULL;
|
|
f();
|
|
}
|
|
}
|
|
}else{
|
|
waiting_for = 1;
|
|
fn_ready_saved = fn_ready;
|
|
wait_till = Timer + ms; // "automatic" overload
|
|
}
|
|
}
|
|
|
|
// macro to open/close/set default state
|
|
// open shutter is 0:0 -> when MCU power is off, shutter "automatically" opens
|
|
#define shutter_close() do{gpio_clear(SHUTTER_PORT, SHUTTER_ON_PIN | SHUTTER_POLARITY_PIN);}while(0)
|
|
#define shutter_open() do{gpio_clear(SHUTTER_PORT, SHUTTER_ON_PIN); \
|
|
gpio_set(SHUTTER_PORT, SHUTTER_POLARITY_PIN);}while(0)
|
|
#define shutter_hiZ() do{gpio_set(SHUTTER_PORT, SHUTTER_ON_PIN | SHUTTER_POLARITY_PIN);}while(0)
|
|
#define shutter_off() do{gpio_set(SHUTTER_PORT, SHUTTER_ON_PIN); \
|
|
gpio_clear(SHUTTER_PORT, SHUTTER_POLARITY_PIN);}while(0)
|
|
#define shutter_error() ((gpio_get(SHUTTER_PORT, SHUTTER_FB_PIN) == 0))
|
|
|
|
/**
|
|
* Make tests for undervoltage & wire breakage
|
|
* this function calls in 2 stages:
|
|
* 1) check undervoltage & set hiZ
|
|
* 2) repeat checking undervoltage & check wire breakage
|
|
* if shutter was uninitialized we open it
|
|
*/
|
|
void shutter_test(){
|
|
//DBG("shutter test\n");
|
|
static shutter_state old_State = SHUTTER_NOTREADY;
|
|
// test for undervoltage
|
|
if(shutter_voltage() < SHUTTER_UNDERVOLTAGE_THRES){
|
|
// ERR("shutter undervoltage\n");
|
|
Shutter_State = SHUTTER_NOTREADY;
|
|
shutter_off();
|
|
return;
|
|
}
|
|
if(Shutter_State != SHUTTER_INITIALIZED){ // first call of this function
|
|
old_State = Shutter_State;
|
|
Shutter_State = SHUTTER_INITIALIZED;
|
|
// test for wire breakage
|
|
// DBG("breakage test\n");
|
|
shutter_hiZ(); // 1,1: breakage test
|
|
shutter_wait_block(SHUTTER_OP_DELAY, shutter_test);
|
|
}else{ // check breakage
|
|
if(shutter_error()){ // ERR==0 -> wire breakage
|
|
// ERR("shutter wire breakage\n");
|
|
Shutter_State = SHUTTER_NOTREADY;
|
|
}else{
|
|
if(old_State == SHUTTER_NOTREADY){
|
|
Shutter_State = SHUTTER_CLOSING; // close shutter on power on
|
|
// DBG("ready!\n");
|
|
}else{
|
|
Shutter_State = old_State;
|
|
// DBG("no errors\n");
|
|
}
|
|
}
|
|
shutter_off();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* after open/close pulse we should return bridge to default state
|
|
* If shutter opened/closed by manual switch we don't need to check EP (reed)
|
|
* 3 stages:
|
|
* 1) check for short-circuit & turn off power of the shutter
|
|
* 2) check for overtemperature or undervoltage
|
|
* 3) common test for undervoltage/breakage
|
|
*/
|
|
void shutter_ready(){
|
|
uint8_t test_err = 0;
|
|
//DBG("shtr ready\n");
|
|
uint32_t shtr_status = gpio_get(SHUTTER_EXT_PORT, SHUTTER_FBSW_PIN); // 0 when opened
|
|
switch (Shutter_State){
|
|
case SHUTTER_CLOSED: // repeated pulse to check errors
|
|
if(shtr_status)
|
|
LED_SHUTTER_CLOSE(); // turn off shutter status LED
|
|
else{
|
|
ERR("shutter is still opened\n");
|
|
//if(!changed_manually)
|
|
Shutter_State = SHUTTER_NOTREADY;
|
|
}
|
|
break;
|
|
case SHUTTER_OPENED:
|
|
if(shutter_error()){
|
|
ERR("shutter overtemperature or undervoltage\n");
|
|
Shutter_State = SHUTTER_NOTREADY;
|
|
}else{
|
|
if(shtr_status == 0)
|
|
LED_SHUTTER_OPEN(); // turn on LED
|
|
else{
|
|
ERR("shutter is still closed\n");
|
|
//if(!changed_manually)
|
|
Shutter_State = SHUTTER_NOTREADY;
|
|
}
|
|
}
|
|
break;
|
|
case SHUTTER_PROC_CLOSING: // closing - set to closed state
|
|
case SHUTTER_PROC_OPENING: // opening - set to opened state
|
|
if(shutter_error()){
|
|
ERR("shutter short-circuit\n");
|
|
Shutter_State = SHUTTER_NOTREADY;
|
|
}else{
|
|
test_err = 1;
|
|
if(Shutter_State == SHUTTER_PROC_CLOSING)
|
|
Shutter_State = SHUTTER_CLOSED;
|
|
if(Shutter_State == SHUTTER_PROC_OPENING)
|
|
Shutter_State = SHUTTER_OPENED;
|
|
}
|
|
break;
|
|
default:
|
|
ERR("wrong shutter state\n");
|
|
print_shutter_state(lastsendfun);
|
|
}
|
|
//changed_manually = 0;
|
|
shutter_off();
|
|
if(Shutter_State == SHUTTER_NOTREADY) return;
|
|
if(test_err){
|
|
//DBG("now test for err\n");
|
|
shutter_wait_nonblock(SHUTTER_DELAY, shutter_ready); // test for overtemp or undervoltage
|
|
}else{
|
|
// wait a lot of time to prevent false detections
|
|
shutter_wait_nonblock(SHUTTER_DELAY, shutter_test);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialisation of shutter ports & test for shutter presense
|
|
* @return 1 if all OK, 0 in case of error
|
|
*/
|
|
shutter_state shutter_init(){
|
|
Shutter_State = SHUTTER_NOTREADY;
|
|
/*
|
|
// setup timer
|
|
rcc_periph_clock_enable(RCC_SHUTTER_TIM);
|
|
//rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_TIM5EN);
|
|
//rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_TIM1EN);
|
|
timer_reset(SHUTTER_TIM);
|
|
// timer have frequency of 1MHz, so, to make pause in Xus set period to X
|
|
// 36MHz of APB1
|
|
timer_set_mode(SHUTTER_TIM, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
|
|
// 72MHz div 72 = 1MHz
|
|
timer_set_prescaler(SHUTTER_TIM, 71);
|
|
timer_one_shot_mode(SHUTTER_TIM); // single pulse mode
|
|
timer_disable_preload(SHUTTER_TIM); // force changing period
|
|
timer_update_on_overflow(SHUTTER_TIM); // generate UEV only on overflow
|
|
timer_enable_update_event(SHUTTER_TIM);
|
|
nvic_enable_irq(NVIC_SHUTTER_IRQ);
|
|
timer_enable_irq(SHUTTER_TIM, TIM_DIER_UIE); // update IRQ enable
|
|
*/
|
|
//DBG("shutter timer ready\n");
|
|
// setup pins
|
|
// on/off & polarity: open drain
|
|
gpio_set_mode(SHUTTER_PORT, GPIO_MODE_OUTPUT_2_MHZ,
|
|
GPIO_CNF_OUTPUT_OPENDRAIN, SHUTTER_ON_PIN | SHUTTER_POLARITY_PIN);
|
|
//DBG("shutter on&polarity ready\n");
|
|
// feedback: floating input
|
|
gpio_set_mode(SHUTTER_PORT, GPIO_MODE_INPUT,
|
|
GPIO_CNF_INPUT_FLOAT, SHUTTER_FB_PIN);
|
|
// Shutter control: input pull up
|
|
// gpio_set_mode(SHUTTER_EXT_PORT, GPIO_MODE_INPUT,
|
|
// GPIO_CNF_INPUT_FLOAT, SHUTTER_CAM_PIN | SHUTTER_MAN_PIN | SHUTTER_FBSW_PIN);
|
|
// gpio_set(SHUTTER_EXT_PORT, SHUTTER_CAM_PIN | SHUTTER_MAN_PIN | SHUTTER_FBSW_PIN); // turn on pull up
|
|
//DBG("shutter fb ready\n");
|
|
shutter_off();
|
|
camera_pin_old_state = (gpio_get(SHUTTER_EXT_PORT, SHUTTER_CAM_PIN)) ? 1 : 0;
|
|
manual_pin_old_state = (gpio_get(SHUTTER_EXT_PORT, SHUTTER_MAN_PIN)) ? 1 : 0;
|
|
//shutter_timer_fn = NULL;
|
|
shutter_wait_block(SHUTTER_OP_DELAY, shutter_test);
|
|
return SHUTTER_INITIALIZED; // we return this state in spite of the shutter isn't really initialized yet
|
|
}
|
|
|
|
/**
|
|
* Finite-state machine processing for shutter
|
|
* (wait for capasitor charge and run needed functions
|
|
*/
|
|
void process_shutter(){
|
|
uint8_t man_pin_state, cam_pin_state, ext_open = 0, ext_close = 0;
|
|
|
|
shutter_wait_nonblock(0, NULL); // check for holded over functions
|
|
|
|
if(Shutter_State == SHUTTER_NOTREADY) return;
|
|
|
|
// test state of external control pins
|
|
cam_pin_state = (gpio_get(SHUTTER_EXT_PORT, SHUTTER_CAM_PIN)) ? 1 : 0;
|
|
if(camera_pin_old_state != cam_pin_state){ // camera signal changed or initialisation
|
|
camera_pin_old_state = cam_pin_state;
|
|
if(cam_pin_state){ // close
|
|
ext_close = 1;
|
|
}else{ // open
|
|
ext_open = 1;
|
|
}
|
|
}
|
|
man_pin_state = (gpio_get(SHUTTER_EXT_PORT, SHUTTER_MAN_PIN)) ? 1 : 0;
|
|
// to avoid opening shutter if user forget to set manual switch to "closed" position
|
|
// all operations with manual switch processed only in changing state of the switch
|
|
if(manual_pin_old_state != man_pin_state){ // user changed switch state -> open/close
|
|
manual_pin_old_state = man_pin_state;
|
|
//changed_manually = 1;
|
|
if(man_pin_state){ // close
|
|
ext_close = 1;
|
|
}else{ // open
|
|
ext_open = 1;
|
|
}
|
|
}
|
|
|
|
// "open" signal have highest priority
|
|
if(ext_open){ // external signal for opening shutter
|
|
if(Shutter_State != SHUTTER_OPENED && Shutter_State != SHUTTER_PROC_OPENING)
|
|
Shutter_State = SHUTTER_OPENING;
|
|
//else
|
|
// changed_manually = 0;
|
|
}else if(ext_close){ // close shutter
|
|
if(Shutter_State != SHUTTER_CLOSED && Shutter_State != SHUTTER_PROC_CLOSING)
|
|
Shutter_State = SHUTTER_CLOSING;
|
|
//else
|
|
// changed_manually = 0;
|
|
}
|
|
|
|
if(Shutter_State != SHUTTER_OPENING && Shutter_State != SHUTTER_CLOSING)
|
|
return;
|
|
if(shutter_voltage() < SHUTTER_UNDERVOLTAGE_THRES){
|
|
ERR("no shutter power source\n");
|
|
Shutter_State = SHUTTER_NOTREADY;
|
|
shutter_off();
|
|
return;
|
|
}
|
|
if(shutter_error()){
|
|
ERR("some shutter error\n");
|
|
Shutter_State = SHUTTER_NOTREADY;
|
|
shutter_off();
|
|
return;
|
|
}
|
|
if(shutter_voltage() < SHUTTER_VOLTAGE_THRES) return; // capasitor isn't charged
|
|
switch (Shutter_State){
|
|
case SHUTTER_OPENING:
|
|
Shutter_State = SHUTTER_PROC_OPENING;
|
|
shutter_open();
|
|
break;
|
|
case SHUTTER_CLOSING:
|
|
Shutter_State = SHUTTER_PROC_CLOSING;
|
|
shutter_close();
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
shutter_wait_nonblock(SHUTTER_DELAY, shutter_ready);
|
|
}
|
|
|
|
/*
|
|
void Shutter_tim_isr(){
|
|
DBG("shutter timer\n");
|
|
void (*fn)() = shutter_timer_fn;
|
|
if(timer_get_flag(SHUTTER_TIM, TIM_SR_UIF)){
|
|
// Clear compare interrupt flag
|
|
timer_clear_flag(SHUTTER_TIM, TIM_SR_UIF);
|
|
shutter_timer_fn = NULL;
|
|
// and run needed function
|
|
if(fn){
|
|
fn();
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
/**
|
|
* printout shutter state
|
|
*/
|
|
void print_shutter_state(sendfun s){
|
|
if(mode == BYTE_MODE) P("shutter ", s);
|
|
else if(mode == LINE_MODE) P("[ " STR_SHTR_STATE " ", s);
|
|
switch (Shutter_State){
|
|
case SHUTTER_INITIALIZED:
|
|
P("testing", s);
|
|
break;
|
|
case SHUTTER_READY:
|
|
P("ready", s);
|
|
break;
|
|
case SHUTTER_OPENED:
|
|
P("opened", s);
|
|
break;
|
|
case SHUTTER_CLOSED:
|
|
P("closed", s);
|
|
break;
|
|
case SHUTTER_OPENING:
|
|
case SHUTTER_CLOSING:
|
|
P("charged for ", s);
|
|
if(Shutter_State == SHUTTER_OPENING) P("opening", s);
|
|
else P("closing", s);
|
|
break;
|
|
case SHUTTER_PROC_OPENING:
|
|
case SHUTTER_PROC_CLOSING:
|
|
P("in process", s);
|
|
break;
|
|
default: // not ready or error
|
|
if(shutter_error()){ // ERR==0 -> wire breakage or something else
|
|
P("error", s);
|
|
}else
|
|
P("not initialised or broken", s);
|
|
}
|
|
P(" (reed ", s);
|
|
if(gpio_get(SHUTTER_EXT_PORT, SHUTTER_FBSW_PIN)){ // closed
|
|
P("closed", s);
|
|
}else{//opened
|
|
P("opened", s);
|
|
}
|
|
if(mode == BYTE_MODE) P(")\n", s);
|
|
else if(mode == LINE_MODE) P(") ]\n", s);
|
|
#ifdef EBUG
|
|
if(mode == BYTE_MODE){
|
|
P("MAN: ",s);
|
|
if(gpio_get(SHUTTER_EXT_PORT, SHUTTER_MAN_PIN)) P("not ",s);
|
|
P("pressed, EXT: ",s);
|
|
if(gpio_get(SHUTTER_EXT_PORT, SHUTTER_CAM_PIN)) P("not ",s);
|
|
P("pressed\n", s);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Try to open/close shutter depending on argument:
|
|
* state == SHUTTER_CLOSING - try to close
|
|
* state == SHUTTER_OPENING - try to open
|
|
* return 1 if state was changed
|
|
*/
|
|
uint8_t shutter_try(shutter_state state){
|
|
uint8_t changestate = 0;
|
|
switch (Shutter_State){ // right states are only OPENED, CLOSED & READY
|
|
case SHUTTER_OPENED:
|
|
if(state == SHUTTER_OPENING){ // try to open opened shutter?
|
|
BYTE_MSG("alerady opened\n");
|
|
}else changestate = 1;
|
|
break;
|
|
case SHUTTER_CLOSED:
|
|
if(state == SHUTTER_CLOSING){ // try to close closed?
|
|
BYTE_MSG("alerady closed\n");
|
|
}else changestate = 1;
|
|
break;
|
|
case SHUTTER_READY:
|
|
changestate = 1; // All OK - change state
|
|
break;
|
|
default: break;
|
|
}
|
|
if(mode == BYTE_MODE) print_shutter_state(lastsendfun);
|
|
if(changestate)
|
|
Shutter_State = state; // all OK, now we can change current state of shutter
|
|
return changestate;
|
|
}
|
|
|