/*
 
 *
 
 *  High Speed Actuator - Free Invoicing Software
 
 *  Copyright (C) 2012  Gerd Bartelt
 
 *
 
 *  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 3 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, see <http://www.gnu.org/licenses/>.
 
 *
 
 */
 
 
 
#include "controller.h"
 
#include "adc.h"
 
#include "pwm.h"
 
 
 
 
 
int32_t meas;
 
int ad_channel_map[4][2];
 
int32_t rdiff;
 
int32_t meas_old[4]={0,0,0,0};
 
int32_t reg = 0;
 
int32_t setpoint[4]={0,0,0,0};
 
int32_t KP = 120; //120
 
int32_t KI = 0;
 
int32_t KD = 300; //-300
 
#define CONTR_LIMIT 1000
 
 
 
/**
 
 * Initialize the controller and configure the analog channels
 
 */
 
void controller_init(void) {
 
 
 
    // Create a table with the index of all analog channels
 
    ad_channel_map[0][0]=3;
 
    ad_channel_map[0][1]=4;
 
 
 
    ad_channel_map[1][0]=2;
 
    ad_channel_map[1][1]=5;
 
 
 
    ad_channel_map[2][0]=1;
 
    ad_channel_map[2][1]=6;
 
 
 
    ad_channel_map[3][0]=0;
 
    ad_channel_map[3][1]=7;
 
 
 
}
 
/**
 
 * Setter for the controllers setpoint
 
 *
 
 * @param
 
 *          channel Channel no from 0 to 3
 
 *          setp  Setpoint from -1000 to +1000
 
 *
 
 */
 
void controller_setSetpoint(int channel, int setp) {
 
    setpoint[channel] = setp;
 
}
 
 
 
/**
 
 * Controller task
 
 * Call this every 100µs
 
 *
 
 * @param
 
 *          channel Channel no from 0 to 3
 
 *
 
 */
 
void controller_task(int channel){
 
 
 
    // Get the sensor value.
 
    meas = adc_getResult(ad_channel_map[channel][0]) - adc_getResult(ad_channel_map[channel][1]);
 
 
 
    // Calculate the difference between setpoint and sensor value
 
    rdiff = setpoint[channel] - meas;
 
 
 
    // The PD regulator with a scaling factor
 
    reg = rdiff *KP + (meas_old[channel]-meas) * KD;
 
    reg /= 32;
 
 
 
    // Store the old value for the D-value
 
    meas_old[channel] = meas;
 
 
 
    // Limit the value
 
    if (reg > +CONTR_LIMIT) reg = +CONTR_LIMIT;
 
    if (reg < -CONTR_LIMIT) reg = -CONTR_LIMIT;
 
 
 
    // Set the PWM output
 
    pwm_set(channel,reg);
 
}