/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "ch.h"
#include "hal.h"
#include "test.h"
#include "serial.h"
#include "gpt.h"
#include <string.h>
#include "keil/GPS_dekoduj.h"
#include <../../os/various/chprintf.h>
#include <chstreams.h.>
/*MAX delka prikazu, ktery uzivatel muze zadat*/
#define MAX_DELKA_PRIKAZU 10
/*Velikost GPS bufferu*/
#define GPS_BUFFER 500
#define PWM_PERIODA_NORMAL 20000
#define PWM_SIRKA_NORMAL PWM_PERIODA_NORMAL/2
/*Pocet opakovani pro jednotlive faze odpalu (pocet = cas[s]*8) pro kompenzaci 8xrychlejsiho casovace na desce STM32F10xRxT01A */
#define POCET_VENTIL (5*8)
#define POCET_LIS (15*8)
#define POCET_ZATAVENI (5*8)
#define POCET_STRECHA (8*8)
#define CEKANI_NA_STRECHU (10*8)
#define CEKANI_NA_LIS (10*8)
/*makra pro cteni switch sensoru*/
#define CTI_STRECHU palReadPad(STRECHA_SENS_PORT, STRECHA_SENS_STATE)
#define CTI_LIS palReadPad(LIS_SENS_PORT, LIS_SENS_STATE)
extern NMEA_GPGGA GPGGA_informace;
Thread *tp_odpal = NULL;
uint8_t uvitaci_zprava[] = "\r\n\r\n* * * * * * * * * * * * * * * * * * * * * * * * * *\r\nVita vas Automaticky Vypoustec Meteobalonu 1.1\r\nZapojeni vyvodu:\r\n\tGPIOB10 - ventil\r\n\tGPIOB11 - lis\r\n\tGPIOB12 - zataveni balonu\r\n\tGPIOB13 - otevreni krytu\r\nPrikazy:\r\n\t<odpal> zahajeni sekvence vypousteni\n\r\t<zrus> zruseni vypousteni\n\r\t<help> napoveda\r\n* * * * * * * * * * * * * * * * * * * * * * * * * *\r\n\r\n";
//static PWMConfig pwmcfg = {
//10000, /* 10kHz PWM clock frequency. */
//PWM_PERIODA_NORMAL, /* PWM period 1S (in ticks). */
/*NULL,
{
{PWM_OUTPUT_ACTIVE_HIGH, NULL},
{PWM_OUTPUT_ACTIVE_HIGH, NULL},
{PWM_OUTPUT_DISABLED, NULL},
{PWM_OUTPUT_DISABLED, NULL}
},
HW dependent part.*/
//0
//};
/*
* Konfigurace USART2
*/
static const SerialConfig USART2_config =
{
/*Speed*/
9600,
/*Initialization value for the CR1 register.*/
0,
/*Initialization value for the CR2 register.*/
USART_CR2_STOP1_BITS | USART_CR2_LINEN,
/*Initialization value for the CR3 register.*/
0
};
/*
* GPT2 callback.
*/
static void gpt2cb(GPTDriver *gptp)
{
(void)gptp;
/* Wakes up the thread.*/
chSysLockFromIsr();
if (tp_odpal != NULL) {
tp_odpal->p_u.rdymsg = (msg_t)50; /* Znaci, ze se vlakno probouzi kvuli preruseni od GPT*/
chSchReadyI(tp_odpal);
tp_odpal = NULL;
}
chSysUnlockFromIsr();
}
/*
*Konfigurace casovace 2
*/
static const GPTConfig gpt2cfg =
{
500, /*500 Hz ? (puvodne 1000Hz) f*/
gpt2cb /*callback fce*/
};
/*
* Vlakno pro blikani diodou
*/
static WORKING_AREA(waThread1, 128);
static msg_t Thread1(void *arg) {
(void)arg;
chRegSetThreadName("blinker");
while (TRUE) {
palClearPad(GPIOB, GPIOB_LED4);
chThdSleepMilliseconds(500);
palSetPad(GPIOB, GPIOB_LED4);
chThdSleepMilliseconds(500);
}
}
/*
* Vlakno pro ovladani odpalovaci sekvence
*/
static WORKING_AREA(waThread_odpal, 128);
static msg_t Thread_odpal(void *arg) {
uint8_t stav = 0; // rika, ve ktere fazi je odpalovani
uint8_t odpal_povolen = 0;
uint8_t odpal_pomocna = 0;
uint16_t pocet_opakovani = 1;
uint16_t perioda_casovace = 500; // changing to 8*500 = 400
(void)arg;
chRegSetThreadName("Odpal_vlakno");
while (TRUE)
{
msg_t msg;
/* Waiting for the IRQ to happen.*/
chSysLock();
tp_odpal = chThdSelf();
chSchGoSleepS(THD_STATE_SUSPENDED);
msg = chThdSelf()->p_u.rdymsg; /* Retrieving the message, optional.*/
chSysUnlock();
/* Perform processing here.*/
if(msg == 1)
{
odpal_povolen = 1;
odpal_pomocna++;
stav = 0;
pocet_opakovani = 1;
}
else if (msg == 2) //Pokud se ma odpal zrusit v prubehu vypousteni
{
/*
* Pro jistotu se vypnou vsechny vystupy pri zruseni odpalu
*/
palClearPad(NFET_OUTPUTS_PORT, GPIOB_PIN10);
palClearPad(NFET_OUTPUTS_PORT, GPIOB_PIN11);
palClearPad(NFET_OUTPUTS_PORT, GPIOB_PIN12);
palClearPad(NFET_OUTPUTS_PORT, GPIOB_PIN13);
palSetPad(IND_LEDS_PORT, LED_STRECHA);
palSetPad(IND_LEDS_PORT, LED_LIS);
palSetPad(IND_LEDS_PORT, LED_VENTIL);
palSetPad(IND_LEDS_PORT, LED_ZATAVENI);
if(odpal_povolen == 1)
chprintf((BaseSequentialStream *)&SD1,"\r\nOdpal zrusen uzivatelem.\r\n");
else
chprintf((BaseSequentialStream *)&SD1,"Odpal nebyl aktivovan.\r\n");
odpal_povolen = 0;
odpal_pomocna = 0;
stav = 0;
pocet_opakovani = 1;
}
else if (msg == 50 && odpal_povolen == 1) // preruseni od GPT
{
odpal_pomocna = 1;
}
if (odpal_povolen == 1 && odpal_pomocna <= 1)
{
odpal_pomocna = 2; // aby nepretekla tato promenna
switch (stav)
{
case 0: // ukonceni tohoto stavu pouze v pripade, ze je otevrena strecha
if (pocet_opakovani == 1)
chprintf((BaseSequentialStream *)&SD1,"Vypousteni zahajeno!\r\n");
if (pocet_opakovani <= POCET_STRECHA)
{
chprintf((BaseSequentialStream *)&SD1,"(1/4)\tOtevirani vika... Strecha: %d, Zbyva: %3d \r",CTI_STRECHU,(POCET_STRECHA-pocet_opakovani));
palSetPad(GPIOB, GPIOB_PIN10);
palClearPad(IND_LEDS_PORT, LED_STRECHA);
gptStartOneShot(&GPTD2,perioda_casovace);
pocet_opakovani++;
if (pocet_opakovani == (POCET_STRECHA+1))
{
chprintf((BaseSequentialStream *)&SD1,"\r\n");
stav++;
pocet_opakovani = 1;
}
}
break;
case 1:
// kontrola strechy - maximalni cas prepalovani
gptStartOneShot(&GPTD2,perioda_casovace);
if (CTI_STRECHU)
{
chprintf((BaseSequentialStream *)&SD1,"Strecha otevrena. Pokracovani v napousteni.\r\n");
pocet_opakovani = 1;
stav++;
}
else
{
if(pocet_opakovani <= CEKANI_NA_STRECHU){
chprintf((BaseSequentialStream *)&SD1,"Cekani na otevreni strechy.\r");
pocet_opakovani++;
}
else { // prekroceni maximalni doby pro odpaleni strechy
palClearPad(NFET_OUTPUTS_PORT, GPIOB_PIN10);
palClearPad(NFET_OUTPUTS_PORT, GPIOB_PIN11);
palClearPad(NFET_OUTPUTS_PORT, GPIOB_PIN12);
palClearPad(NFET_OUTPUTS_PORT, GPIOB_PIN13);
palSetPad(IND_LEDS_PORT, LED_STRECHA);
palSetPad(IND_LEDS_PORT, LED_LIS);
palSetPad(IND_LEDS_PORT, LED_VENTIL);
palSetPad(IND_LEDS_PORT, LED_ZATAVENI);
chprintf((BaseSequentialStream *)&SD1,"\r\nNelze otevrit strechu.\r\n");
odpal_povolen = 0;
odpal_pomocna = 0;
stav = 0;
pocet_opakovani = 1;
}
}
break;
case 2:
if (pocet_opakovani <= POCET_VENTIL)
{
palClearPad(GPIOB, GPIOB_PIN10);
palSetPad(IND_LEDS_PORT, LED_STRECHA);
palSetPad(GPIOB, GPIOB_PIN11);
palClearPad(IND_LEDS_PORT, LED_VENTIL);
chprintf((BaseSequentialStream *)&SD1,"(2/4)\tVentil otevren -> nafukovani balonu... Strecha: %d, Zbyva: %3d\r",CTI_STRECHU,(POCET_VENTIL-pocet_opakovani));
gptStartOneShot(&GPTD2,perioda_casovace);
pocet_opakovani++;
if (pocet_opakovani == (POCET_VENTIL+1))
{
chprintf((BaseSequentialStream *)&SD1,"\r\n");
stav++;
pocet_opakovani = 1;
}
}
break;
case 3:
if (pocet_opakovani <= POCET_LIS)
{
palClearPad(GPIOB, GPIOB_PIN11);
palSetPad(IND_LEDS_PORT, LED_VENTIL);
palSetPad(GPIOB, GPIOB_PIN12);
palClearPad(IND_LEDS_PORT, LED_LIS);
chprintf((BaseSequentialStream *)&SD1,"(3/4)\tPrepalovani lisu... Lis: %d, Zbyva: %3d\r",CTI_LIS,(POCET_LIS-pocet_opakovani));
gptStartOneShot(&GPTD2,perioda_casovace);
pocet_opakovani++;
if (pocet_opakovani == (POCET_LIS+1))
{
chprintf((BaseSequentialStream *)&SD1,"\r\n");
stav++;
pocet_opakovani = 1;
}
}
break;
case 4: // kontrola prepaleni lisu
gptStartOneShot(&GPTD2,perioda_casovace);
if (CTI_LIS)
{
chprintf((BaseSequentialStream *)&SD1,"Lis stlacen. Pokracovani v pretavovani.\r\n");
pocet_opakovani = 1;
stav++;
}
else
{
if(pocet_opakovani <= CEKANI_NA_LIS){
chprintf((BaseSequentialStream *)&SD1,"Cekani na stlaceni lisu.\r");
pocet_opakovani++;
}
else { // prekroceni maximalni doby pro slisovani
palClearPad(NFET_OUTPUTS_PORT, GPIOB_PIN10);
palClearPad(NFET_OUTPUTS_PORT, GPIOB_PIN11);
palClearPad(NFET_OUTPUTS_PORT, GPIOB_PIN12);
palClearPad(NFET_OUTPUTS_PORT, GPIOB_PIN13);
palSetPad(IND_LEDS_PORT, LED_STRECHA);
palSetPad(IND_LEDS_PORT, LED_LIS);
palSetPad(IND_LEDS_PORT, LED_VENTIL);
palSetPad(IND_LEDS_PORT, LED_ZATAVENI);
chprintf((BaseSequentialStream *)&SD1,"\r\nNelze spustit lis.\r\n");
odpal_povolen = 0;
odpal_pomocna = 0;
stav = 0;
pocet_opakovani = 1;
}
}
break;
case 5:
if (pocet_opakovani <= POCET_ZATAVENI)
{
palClearPad(GPIOB, GPIOB_PIN12);
palSetPad(IND_LEDS_PORT, LED_LIS);
palSetPad(GPIOB, GPIOB_PIN13);
palClearPad(IND_LEDS_PORT, LED_ZATAVENI);
chprintf((BaseSequentialStream *)&SD1,"(4/4)\tZatavovani balonu... Lis: %d, Zbyva: %3d \r",CTI_LIS,(POCET_ZATAVENI-pocet_opakovani));
gptStartOneShot(&GPTD2,perioda_casovace);
pocet_opakovani++;
if (pocet_opakovani == (POCET_ZATAVENI+1))
{
chprintf((BaseSequentialStream *)&SD1,"\r\n");
stav++;
pocet_opakovani = 1;
}
}
break;
case 6:
palClearPad(GPIOB, GPIOB_PIN13);
palSetPad(IND_LEDS_PORT, LED_ZATAVENI);
chprintf((BaseSequentialStream *)&SD1,"Vypousteni ukonceno!\r\n");
odpal_povolen = 0;
odpal_pomocna = 0;
stav = 0;
break;
default:
chprintf((BaseSequentialStream *)&SD1,"NIC!\r\n");
break;
}
}
}
}
/*
* Vlakno pro obsluhu GPS prijimace
*/
static WORKING_AREA(waThread_GPS, 768);
static msg_t Thread_GPS(void *arg) {
/*
* Nacita se jen nekolik NMEA zprav, aby se neplytvalo pameti na ulozeni kompletniho
* setu s tím rizikem, ze se nekdy nenacte aktualni informace o poloze.
*/
uint8_t inBuffer[GPS_BUFFER];
char *zacatek_retezce;
char *konec_retezce;
uint8_t pocet_znaku;
uint8_t NMEA_zprava[100];
(void)arg;
chRegSetThreadName("GPS_NMEA");
while (TRUE) {
chThdSleepMilliseconds(1000); //neni potreba data vycitat rychleji
sdRead(&SD2,inBuffer,GPS_BUFFER);
/*
*Nejprve se vycte cast NMEA dat, pote se vyhleda retezec GPGGA zpravy, ta se vyparsuje a pomoci fce
*dekoduj_zpravu_GPS, ktera vyparsuje data o poloze a jine, a ulozi je do struktury GPGGA_informace.
*/
if ((zacatek_retezce = strstr((char *)inBuffer,"$GPGGA")) != NULL)
{
if ((konec_retezce = strstr(zacatek_retezce,"*")) != NULL)
{
pocet_znaku = (konec_retezce-zacatek_retezce)/sizeof(char);
if (pocet_znaku > 100)
{
pocet_znaku = 100;
}
strncpy((char *)NMEA_zprava,zacatek_retezce,pocet_znaku);
dekoduj_zpravu_GPS(&NMEA_zprava[0],pocet_znaku);
sdWrite(&SD2,"Latitude: ",sizeof("Latitude: ")/sizeof(char));
sdWrite(&SD2,GPGGA_informace.Latitude,sizeof(GPGGA_informace.Latitude)/sizeof(uint8_t));
sdWrite(&SD2,"\r\n",2);
sdWrite(&SD2,"Longitude: ",sizeof("Longitude: ")/sizeof(char));
sdWrite(&SD2,GPGGA_informace.Longitude,sizeof(GPGGA_informace.Longitude)/sizeof(uint8_t));
sdWrite(&SD2,"\r\n",2);
sdWrite(&SD2,"Altitude: ",sizeof("Altitude: ")/sizeof(char));
sdWrite(&SD2,GPGGA_informace.Altitude,sizeof(GPGGA_informace.Altitude)/sizeof(uint8_t));
sdWrite(&SD2,"\r\n",2);
sdWrite(&SD2,"Status: ",sizeof("Status: ")/sizeof(char));
sdWrite(&SD2,&GPGGA_informace.Status_GPS,sizeof(GPGGA_informace.Status_GPS)/sizeof(uint8_t));
sdWrite(&SD2,"\r\n",2);
sdWrite(&SD2,NMEA_zprava,pocet_znaku);
sdWrite(&SD2,"\r\n",2);
}
else
{
sdWrite(&SD2,"\r\n",2);
sdWrite(&SD2,"Nenalezen ukoncovaci znak NMEA zpravy *\r\n",sizeof("Nenalezen ukoncovaci znak NMEA zpravy *\r\n")/sizeof(char));
sdWrite(&SD2,inBuffer,GPS_BUFFER);
}
}
else
sdWrite(&SD2,"Nenalezen zacatek GPGGA zpravy\r\n",sizeof("Nenalezen zacatek GPGGA zpravy\r\n")/sizeof(char));
}
}
void dekodujPrikaz(char *prikaz)
{
if(strcmp(prikaz,"odpal") == 0)
{
/* Wakes up the thread.*/
chSysLockFromIsr();
if (tp_odpal != NULL) {
tp_odpal->p_u.rdymsg = (msg_t)1; /* odpal povolen*/
chSchReadyI(tp_odpal);
tp_odpal = NULL;
}
chSysUnlockFromIsr();
}
else if (strcmp(prikaz,"zrus") == 0)
{
/* Wakes up the thread.*/
chSysLockFromIsr();
if (tp_odpal != NULL) {
tp_odpal->p_u.rdymsg = (msg_t)2; /* zakazano pokracovat v odpalovaci sekvenci*/
chSchReadyI(tp_odpal);
tp_odpal = NULL;
}
chSysUnlockFromIsr();
}
else if (strcmp(prikaz,"help") == 0)
{
sdWrite(&SD1, uvitaci_zprava, sizeof(uvitaci_zprava)/sizeof(uint8_t));
}
else
{
uint8_t zp_neplatny[] = "Neplatny prikaz!\r\n\t<odpal> pro zahajeni sekvence\n\r\t<zrus> pro zruseni vypousteni\n\r";
sdWrite(&SD1,zp_neplatny,sizeof(zp_neplatny)/sizeof(uint8_t));
palTogglePad(GPIOB, GPIOB_LED3);
}
}
/*
* Application entry point.
*/
int main(void) {
uint8_t znaky[20];
char prikaz[MAX_DELKA_PRIKAZU + 1];
uint8_t pocet_znaku = 0;
/*
* System initializations.
* - HAL initialization, this also initializes the configured device drivers
* and performs the board-specific initializations.
* - Kernel initialization, the main() function becomes a thread and the
* RTOS is active.
*/
halInit();
chSysInit();
/*
* Activates the serial driver 1 using the driver default configuration.
* PA9 and PA10 are routed to USART1.
* Komunikace s uzivatelem
*/
sdStart(&SD1, NULL);
palSetPadMode(GPIOA, 9, PAL_MODE_STM32_ALTERNATE_OPENDRAIN); //TX
//palSetPadMode(GPIOA, 10, PAL_MODE_STM32_ALTERNATE_OPENDRAIN); //RX
/*
* Activates the serial driver 2 using the driver default configuration.
* PA2 and PA3 are routed to USART2.
*GPS
*/
sdStart(&SD2, &USART2_config);
palSetPadMode(GPIOA, 2, PAL_MODE_STM32_ALTERNATE_OPENDRAIN); //TX
palSetPadMode(GPIOA, 3, PAL_MODE_STM32_ALTERNATE_OPENDRAIN); //RX - overrides board.h PadValues
/*
* LED na vyvojove desce
*/
palSetPadMode(GPIOB, GPIOB_LED3, PAL_MODE_OUTPUT_PUSHPULL);
/*
* Initializes the PWM driver 4, routes the TIM4 outputs to the board LEDs.
*/
/*pwmStart(&PWMD4, &pwmcfg);
palSetPadMode(GPIOB, GPIOB_LED4, PAL_MODE_STM32_ALTERNATE_OPENDRAIN);
pwmEnableChannel(&PWMD4,0,PWM_SIRKA_NORMAL);*/
/*
* Porty pro vypousteci sekvenci
*/
palSetPadMode(GPIOB, GPIOB_PIN10, PAL_MODE_OUTPUT_PUSHPULL);
palClearPad(GPIOB, GPIOB_PIN10);
palSetPadMode(GPIOB, GPIOB_PIN11, PAL_MODE_OUTPUT_PUSHPULL);
palClearPad(GPIOB, GPIOB_PIN11);
palSetPadMode(GPIOB, GPIOB_PIN12, PAL_MODE_OUTPUT_PUSHPULL);
palClearPad(GPIOB, GPIOB_PIN12);
palSetPadMode(GPIOB, GPIOB_PIN13, PAL_MODE_OUTPUT_PUSHPULL);
palClearPad(GPIOB, GPIOB_PIN13);
palSetPad(IND_LEDS_PORT, LED_STRECHA);
palSetPad(IND_LEDS_PORT, LED_LIS);
palSetPad(IND_LEDS_PORT, LED_VENTIL);
palSetPad(IND_LEDS_PORT, LED_ZATAVENI);
/*
* Aktivuje timer2 a timer3 prejde tak do aktivniho stavu
*/
gptStart(&GPTD2,&gpt2cfg);
chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);
/*
* Vytvori vlakno pro prijem dat z GPS modulu
*/
chThdCreateStatic(waThread_GPS, sizeof(waThread_GPS), NORMALPRIO, Thread_GPS, NULL);
/*
* Vytvori vlakno pro odpalovaci sekvenci
*/
chThdCreateStatic (waThread_odpal, sizeof(waThread_odpal), NORMALPRIO, Thread_odpal, NULL);
sdWrite(&SD1, uvitaci_zprava, sizeof(uvitaci_zprava)/sizeof(uint8_t));
/*
* Normal main() thread activity, in this demo it does nothing except
* sleeping in a loop and check the button state, when the button is
* pressed the test procedure is launched with output on the serial
* driver 1.
*/
while (TRUE) {
sdRead(&SD1,znaky,1);
/*Kdyz uzivatel stiskne enter -> dekoduj a vykonej prikaz, nebo pokud je prikaz delsi, nez by mel byt,
*prestane ukladat a upozorni uzivatele
*/
if (znaky[0] == '\r' || pocet_znaku >= MAX_DELKA_PRIKAZU)
{
pocet_znaku = 0;
dekodujPrikaz(prikaz);
prikaz[0] = 0;
}
/*Uklada prikaz*/
else
{
prikaz[pocet_znaku + 1] = 0;
prikaz[pocet_znaku++] = znaky[0];
}
}
}