/*
 * process.c
 *
 *  Created on: Mar 4, 2012
 *      Author: qwer1
 */

#include "process.h"
#include "config.h"
#include "adc.h"
#include "pid.h"
#include "usart.h"
#include "ul_bcd.h"
#include "sound.h"

struct process_struct process;
struct ptx *ptx_process;

void setup_process(void) {
	//start work process control thread
	ptx_process = ptx_add(pt_process, NULL, PTX_FLAG_RUN | PTX_FLAG_SYNC_1MS);
}

void process_restart(void) {
	//restart work flow process
	PT_INIT(&(ptx_process->pt));
	ptx_start(ptx_process);

	//reset PID regulators
	pids_init();

	//reset program counter
	process.program_time = 0;
}

PT_THREAD( pt_process( struct pt *pt, struct ptx *ptx ) ) {
	PT_BEGIN(pt);
	while (1) {

		if (process.run) { //RUN mode ?

			//start from step 0
			config.current_step = 0;
			//current step data pointer
			process.step = &config.programs[config.current_program][0];
			//reset process timer
			process.step_timer = 0;

			//play start sound
			snd_buf_reset();
			snd_buf_add(SND_STEP_START);

			//program flow loop
			do {
				//not last step ? Setup initial parameters
				if (process.step->time > 0) {

					U16 timer = process.step->time;

					//calculate delta T for all sensors
					for (U8 i=0; i<T_TC_NUM; i++) {
						if ((process.step->t_set[i] > 50)&&(t_is_ok(t_tc[i]))) {
							process.t_set_last[i] = process.step->t_set[i] * 1000L;
							//infinite level set
							if (process.step->time == 999) {
							    process.t_step[i] = 0;
								process.t_set_current[i] = process.t_set_last[i];
							} else {
								process.t_set_current[i] = t_tc[i] * 100L;
							    //1st step - calculate parameters starting from 0 degree
								if (config.current_step == 0) {
									process.t_step[i] = process.t_set_last[i] / process.step->time;
									//calculate new step time when heating not from 0
									S16 t = (process.t_set_last[i] - process.t_set_current[i]) / process.t_step[i];
									if (t == 0) t = 1;
									else if (t < 0) t = -t;
									//for 1st sensor use new time
									if (i == 0) timer = t;
									else {
										//for other sensors use longest time
										if (t > timer) timer = t;
									}
							    } else {
									process.t_step[i] =
										(process.t_set_last[i] - process.t_set_current[i]) /
											process.step->time;
							    }
							}
						} else {
							//direct power regulation 2..100%
							process.t_set_last[i] = process.step->t_set[i];
							process.t_set_current[i] = process.step->t_set[i];
							process.t_step[i] = 0;
						}
					}

					//process temperature slope for current step
					for (process.step_timer = timer; process.step_timer>0; process.step_timer--) {

						for (U8 i=0; i<T_TC_NUM; i++) {
							//increment setpoint temperature
							if (process.t_step[i] == 0) process.t_set_current[i] = process.t_set_last[i];
							else process.t_set_current[i] += process.t_step[i];

							if (process.t_step[i] >= 0) { //limit maximum on positive slope
								if (process.t_set_current[i] > process.t_set_last[i])
									process.t_set_current[i] = process.t_set_last[i];
							} else { //limit minimum on negative slope
								if (process.t_set_current[i] < process.t_set_last[i])
									process.t_set_current[i] = process.t_set_last[i];
							}
						}

						//update PID regulators
						pids_update();

						//log process parameters to USART
						if (usart_modbus_mode == 0) {
							//program time
							NUM2ASC_S32(process.program_time, &usart_tmp_buf[4], 5, 0, 1, 1);
							RBUF_WR_BUF8(&usart_tx_buf, &usart_tmp_buf[0], 5);
							RBUF_WR(&usart_tx_buf, ';');

							//current temperatures
							for (U8 i=0; i<T_TC_NUM; i++) {
								NUM2ASC_S32(t_tc[i], &usart_tmp_buf[6], 7, 2, 1, 1);
								RBUF_WR_BUF8(&usart_tx_buf, &usart_tmp_buf[0], 7);
								RBUF_WR(&usart_tx_buf, ';');
							}

							//line end
							RBUF_WR(&usart_tx_buf, 0x0D);
							RBUF_WR(&usart_tx_buf, 0x0A);
						}

						//delay 1sec
						PTX_DELAY_MS(1000);

						//increment program counter
						process.program_time++;
						
						//step time == 999sec - do infinite loop
						if (process.step->time == 999)
						    process.step_timer++;
					}
				} else config.current_step = 9;

				//go to next program step
				process.step++;
				config.current_step++;

				//play end of step sound
				if (config.current_step < 10) {
					snd_buf_add(SND_STEP_STOP);
				}

			} while (config.current_step < 10);

			//play end of profile sound
			snd_buf_reset();
			snd_buf_addzn((U16 *)&snd_program_stop[0], 4);

			//goto STOP mode
			config.current_step = 0;
			process.run = 0;
		} else {
		}
		PT_YIELD(pt);
	}
	PT_END(pt);
}
