Browse Source

Merge branch 'master' of https://github.com/catsup/OpenChronos into catsup-master

master
Daniel Poelzleithner 12 years ago
parent
commit
6408ca9a95
  1. 48
      README
  2. 6
      driver/buzzer.c
  3. 1
      driver/buzzer.h
  4. 16
      driver/timer.c
  5. 4
      ezchronos.c
  6. 13
      logic/altitude.c
  7. 10
      logic/menu.c
  8. 574
      logic/vario.c
  9. 27
      logic/vario.h

48
README

@ -1,3 +1,51 @@
This fork adds a variometer, an instrument indicating vertical speed,
essentially for use in free flight (paragliding, hang gliding, ...).
Initially based on the vario source coded by dkm, I ended up rewriting
that module completely.
- Pressing the "v" (down) button cycles between displays as follows:
* vario (in m/s)
Displays a signed fractional value representing the ascent or
descent speed in meters per second.
* vario (in Pascal)
Displays a signed integer value representing the ascent or
descent speed in Pascal/second.
* pressure (in hPa)
Displays a signed fraction representing the pressure measured at
the current altitude.
* max Vz (in m/s)
Displays the maximum vertical speed in meters/second.
* min Vz (in m/s)
Displays the minimum vertical speed in meters/second.
- A long press on the "#" button performs a context sensitive function:
* during vario display, changes the vario sound mode:
Off (default, no symbol displayed)
Ascent 0 (start beeping at 0.0m/s, beeper1 and beeper2 symbols
displayed)
Ascent 1 (start beeping at 0.1m/s, beeper1 symbol displayed)
Both (beep for up or down, beeper1 and beeper2 symbols
displayed)
Tone frequency, number and duration of beeps depend on climb rate.
* during max/min Vz display, resets both the max and min values.
- The "record" icon is flashed at one second intervals, indicating that
the watch is in vario mode and receiving pressure measurements.
Note that the upper line must be in altimeter mode for the vario to
work, as it relies on updates from the altimeter. If the altimeter
is not active, the vario display shows "noAlt".
== Status ==
Works, but in development :-)

6
driver/buzzer.c

@ -129,7 +129,11 @@ void start_buzzer(u8 cycles, u16 on_time, u16 off_time)
}
}
void start_buzzer_steps(u8 cycles, u16 on_time, u16 off_time, u8 steps )
{
sBuzzer.steps = steps;
start_buzzer( cycles, on_time, off_time );
}
// *************************************************************************************************
// @fn toggle_buzzer

1
driver/buzzer.h

@ -45,6 +45,7 @@
// Prototypes section
extern void reset_buzzer(void);
extern void start_buzzer(u8 cycles, u16 on_time, u16 off_time);
extern void start_buzzer_steps(u8 cycles, u16 on_time, u16 off_time, u8 steps);
extern void stop_buzzer(void);
extern void toggle_buzzer(void);
extern u8 is_buzzer(void);

16
driver/timer.c

@ -65,14 +65,6 @@
#include "acceleration.h"
#endif
#ifdef CONFIG_PROUT
#include "prout.h"
#endif
#ifdef CONFIG_VARIO
#include "vario.h"
#endif
//pfs
#ifndef ELIMINATE_BLUEROBIN
#include "bluerobin.h"
@ -387,14 +379,6 @@ __interrupt void TIMER0_A0_ISR(void)
}
}
#ifdef CONFIG_PROUT
if (is_prout()) prout_tick();
#endif
#ifdef CONFIG_VARIO
if(is_vario()) vario_tick();
#endif
#ifdef CONFIG_STRENGTH
// One more second gone by.
if(is_strength())

4
ezchronos.c

@ -407,10 +407,6 @@ void init_global_variables(void)
reset_prout();
#endif
#ifdef CONFIG_VARIO
reset_vario();
#endif
#ifdef CONFIG_PHASE_CLOCK
// default program
sPhase.program = 0;

13
logic/altitude.c

@ -53,6 +53,9 @@
// logic
#include "user.h"
#ifdef CONFIG_VARIO
# include "vario.h"
#endif
// *************************************************************************************************
@ -243,13 +246,19 @@ void do_altitude_measurement(u8 filter)
// Store average pressure
sAlt.pressure = pressure;
}
// Convert pressure (Pa) and temperature (?K) to altitude (m)
// Convert pressure (Pa) and temperature (?K) to altitude (m).
#ifdef FIXEDPOINT
sAlt.altitude = conv_pa_to_altitude(sAlt.pressure, sAlt.temperature);
#else
sAlt.altitude = conv_pa_to_meter(sAlt.pressure, sAlt.temperature);
#endif
#ifdef CONFIG_VARIO
// Stash a copy to the vario after filtering. If doing so before, there
// is just too much unnecessary fluctuation, up to +/- 7Pa seen.
vario_p_write( pressure );
#endif
}

10
logic/menu.c

@ -264,14 +264,14 @@ const struct menu menu_L2_Date =
//Line 2 - Vario
const struct menu menu_L2_Vario =
{
FUNCTION(sx_vario), // direct function
FUNCTION(mx_vario), // sub menu function
FUNCTION(sx_vario), // direct function
FUNCTION(mx_vario), // sub menu function
FUNCTION(menu_skip_next), // next item function
FUNCTION(display_vario), // display function
FUNCTION(update_vario), // new display data
FUNCTION(display_vario), // display function
FUNCTION(update_time), // refresh display data once every second
};
#endif
// Line2 - Stopwatch
const struct menu menu_L2_Stopwatch =
{

574
logic/vario.c

@ -1,6 +1,9 @@
/*
Vario function for ez430 chronos watch.
Copyright (C) 2010 Marc Poulhiès <dkm@kataplop.net>
Altivario function for ez430 chronos watch.
Copyright (C) 2011, Marc Bongartz <mbong@free.fr>
Build environment Copyright (C) 2010 Marc Poulhi<E8>s <dkm@kataplop.net>
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
@ -55,152 +58,499 @@
#ifdef CONFIG_VARIO
// driver
#include "altitude.h"
#include "display.h"
#include "vti_ps.h"
#include "ports.h"
#include "timer.h"
#include "stopwatch.h"
#include "buzzer.h"
// logic
#include "user.h"
#include "altitude.h"
#include "vario.h"
#include "menu.h"
struct vario svario;
void hist_add(s16 alt);
u8 hist_ready(void);
//
// Module internal definitions.
//
// Vario compile time options, saving space if needed.
#define VARIO_ALT_PA 0 /* 32 bytes - display vario in Pascal */
#define VARIO_PA 1 /* 30 bytes - display pressure in hPa */
#define VARIO_VZ 1 /* 110 bytes - display Vz min/ max */
#define VARIO_ALTMAX 1 /* 64 bytes - display max altitude */
#define VARIO_F_TIME 1 /* 216 bytes - display flight time */
//
// Global struct with all our variables.
//
struct
{
u32 pressure; // updated by altitude.c - need a mutex ?
u32 prev_pa; // pressure at last scan
u8 p_valid; // mutex for pressure field
u8 view_mode; // view mode, controlled by "v" key
u8 beep_mode; // beeper mode, controlled by "#" key
struct
{
#if VARIO_VZ
s16 vzmin; // Vz min in Pascal
s16 vzmax; // Vz max in Pascal
#endif
#if VARIO_ALTMAX
u16 altmax; // altitude max - 32767m should be enough.
#endif
#if VARIO_F_TIME
struct {
u8 hh; // 00-99
u8 mm; // 00-59
u8 ss; // 00-59
} f_time; // flight time
#endif
} stats;
} G_vario;
#define HIST_GET_OLD() svario.hist_alts[(svario.hist_pos+1)%VARIO_HIST_SIZE]
#define HIST_GET_NEW() svario.hist_alts[svario.hist_pos]
//
// Note the beepmode enum changes are reflected in the beepmode symbol.
// For visual feedback during settings, the beeper2 symbol is turned on
// when beepmode ASCENT_0 or BOTH are selected. Update the corresponding
// logic if you change the beepmode enum order or add a new enum value.
//
enum
{
VARIO_BEEPMODE_OFF = 0, // default beep mode
VARIO_BEEPMODE_ASCENT_0, // ascent only, beep at zero
VARIO_BEEPMODE_ASCENT_1, // ascent only, beep at one
VARIO_BEEPMODE_BOTH, // ascent and descent
VARIO_BEEPMODE_MAX
};
enum
{
VARIO_VIEWMODE_ALT_M = 0, // Vario in m/s, default view mode
#if VARIO_ALT_PA
VARIO_VIEWMODE_ALT_PA, // Vario in Pascal
#endif
#if VARIO_PA
VARIO_VIEWMODE_PA, // Display current pressure
#endif
#if VARIO_VZ
VARIO_VIEWMODE_VZMAX, // Max Vario (positive)
VARIO_VIEWMODE_VZMIN, // Max Vario (positive)
#endif
#if VARIO_ALTMAX
VARIO_VIEWMODE_ALT_MAX, // Max altitude
#endif
#if VARIO_F_TIME
VARIO_VIEWMODE_F_TIME, // Flight time (since stats reset)
#endif
VARIO_VIEWMODE_MAX
};
/**
* called every sec
*/
void vario_tick()
//
// Clear statistics
//
static inline void
_clear_stats( void )
{
if (is_altitude_measurement()){
hist_add(sAlt.altitude);
if (!hist_ready()){
display_symbol(LCD_ICON_RECORD, SEG_ON_BLINK_ON);
} else {
display_symbol(LCD_ICON_RECORD, SEG_OFF);
}
}
display_vario(0, 0);
#if 0000 // We save 10 bytes by using memset() if VZ, ALTMAX and F_TIME are enabled.
#if VARIO_VZ
G_vario.stats.vzmin = 0;
G_vario.stats.vzmax = 0;
#endif
#if VARIO_ALTMAX
G_vario.stats.altmax = 0;
#endif
#if VARIO_F_TIME
G_vario.stats.f_time.hh = 0;
G_vario.stats.f_time.mm = 0;
G_vario.stats.f_time.ss = 0;
#endif
#else // initialise individual fields or use memset ?
memset( &G_vario.stats, 0, sizeof( G_vario.stats ) );
#endif // using memset.
}
u8 is_vario(void)
// "v" button press changes display mode
extern void
sx_vario(u8 line)
{
return (svario.state == VARIO_RUN && (ptrMenu_L2 == &menu_L2_Vario));
G_vario.view_mode++;
G_vario.view_mode %= VARIO_VIEWMODE_MAX;
}
void update_vario()
//
// Long "#" press will turn on/off vario sound if in vario display,
// or clear stats if in stats view mode.
//
extern void
mx_vario(u8 line)
{
switch( G_vario.view_mode )
{
case VARIO_VIEWMODE_ALT_M:
#if VARIO_ALT_PA
case VARIO_VIEWMODE_ALT_PA:
#endif
G_vario.beep_mode++;
G_vario.beep_mode %= VARIO_BEEPMODE_MAX;
break;
#if VARIO_VZ
case VARIO_VIEWMODE_VZMAX:
case VARIO_VIEWMODE_VZMIN:
#endif
# if VARIO_ALTMAX
case VARIO_VIEWMODE_ALT_MAX:
#endif
#if VARIO_F_TIME
case VARIO_VIEWMODE_F_TIME:
#endif
_clear_stats();
break;
#if VARIO_PA
case VARIO_VIEWMODE_PA: // no settings for pressure display
#endif
case VARIO_VIEWMODE_MAX:
break;
}
}
void start_vario()
//
// Mutex for accessing G_vario.pressure from altitude.c (write) and vario.c (read)
// This prevents badly timed updates, for example on button press. It also helped
// me figure a problem with calls to display_vario() from interrupt level.
//
extern void
vario_p_write( u32 p )
{
svario.state = VARIO_RUN;
display_symbol(LCD_ICON_HEART, SEG_ON_BLINK_ON);
if ( !G_vario.p_valid )
{
G_vario.pressure = p;
G_vario.p_valid++;
}
else
{
//
// Pressure has not been read by the vario (called once per second)
// since last write from altimeter (called about once every second in
// ultra low power mode, more often for other modes, or on demand for
// low power with external trigger mode), average in the new pressure
// value.
//
G_vario.pressure = (G_vario.pressure + p) >> 1;
}
}
void stop_vario()
int vario_p_read( u32 *retp )
{
svario.state = VARIO_STOP;
display_symbol(LCD_ICON_HEART, SEG_OFF);
// Call draw routine immediately
display_vario(LINE2, DISPLAY_LINE_UPDATE_FULL);
if ( G_vario.p_valid )
{
*retp = G_vario.pressure;
G_vario.p_valid = 0;
return 0; // success, a new pressure value is available.
}
return 1; // error, no new pressure value available.
}
void sx_vario(u8 line)
//
// Produce a sound depending on the ascent/descent rate.
//
void chirp( s16 pdiff )
{
if (button.flag.down)
{
if (svario.state == VARIO_STOP){
start_vario();
} else {
stop_vario();
}
}
const u8 center_steps = 8;
const u8 range_steps = 5;
u8 bsteps;
u8 nchirps;
u16 on_time;
//
// Buzzer steps (see driver/buzzer) 3..23 provide a frequency
// of 4096Hz..682Hz, well within the human audible range. But
// the lower frequencies have a rather faint volume, may not
// be ideal in flight. Using 3..13 (4096..1170Hz).
//
bsteps = center_steps - (pdiff % range_steps); // buzzer steps
if ( pdiff < 0 ) pdiff *= -1; // need positive value now
nchirps = 1 + (pdiff / range_steps); // number of chirps.
//
// Make sure we make our noises in less than 1s, before the next
// update comes along.
//
if ( nchirps > 50 ) nchirps = 50; // Wouah, 25m/s - up or down?
on_time = 500 / nchirps; // 500ms on time max, half for off time
start_buzzer_steps( nchirps,
CONV_MS_TO_TICKS( on_time ),
CONV_MS_TO_TICKS( on_time / 2 ),
bsteps );
}
void mx_vario(u8 line)
//
// _display_signed() - display a signed value on the second line.
//
// If is_fraction is false, display value on the second line, nnnnnn
// Otherwise display value as fraction on the second line, nnnn.nn
//
// Used to display pressure (in Pascal) as hPa and cm/s as m/s.
//
static void
_display_signed( s32 value, u8 is_fraction )
{
u8 *str;
int i;
int is_neg;
is_neg = ( value < 0 );
if ( is_neg )
{
is_neg = 1;
value *= -1;
}
str = itoa( value, 6, (is_fraction) ? 3 : 5 );
for ( i = 0; (is_neg && (str[i] == ' ')); i++ )
{
if (str[i+1] != ' ')
str[i] = '-';
}
display_chars( LCD_SEG_L2_5_0, str, SEG_ON );
if ( is_fraction )
display_symbol( LCD_SEG_L2_DP, SEG_ON );
}
void display_vario(u8 line, u8 update)
//
// Convert barometric value to vz.
// This really depends on altitude and temp, also humidity, but for
// a rough estimation we can take 1Pa = 10cm (0.1m)
//
// TBS -- allow non-metric display...
//
static inline s32
_pascal_to_vz( s32 pa )
{
if (svario.state == VARIO_STOP) {
display_chars(LCD_SEG_L2_5_0, (u8*) " idle", SEG_ON);
} else if (is_altitude_measurement()){
if (!hist_ready()) {
display_chars(LCD_SEG_L2_5_0, (u8*)" wait", SEG_ON_BLINK_ON);
} else {
u8 *str;
s16 diff = HIST_GET_OLD() - HIST_GET_NEW();
u8 is_neg = 0;
u8 i;
if (diff == 0){
display_chars(LCD_SEG_L2_5_0, (u8*) " 0", SEG_ON);
} else {
if (diff < 0){
is_neg = 1;
diff = diff*(-1);
}
diff = diff / VARIO_HIST_SIZE;
str = itoa(diff, 6, 7);
for (i=0; i<7; i++){
if (str[i] == '0' || str[i] == ' '){
if (is_neg)
str[i] = '-';
else
str[i] = ' ';
} else {
break;
}
}
display_chars(LCD_SEG_L2_5_0, str, SEG_ON);
}
}
} else {
display_chars(LCD_SEG_L2_5_0, (u8*) " NOALT", SEG_ON);
}
return pa * 10;
}
u8 hist_ready(void) {
return (svario.hist_count == VARIO_HIST_SIZE);
//
// Common function to turn off various symbols we use in our view modes.
//
void
_display_l2_clean( void )
{
#if ( VARIO_VZ || VARIO_ALTMAX )
display_symbol( LCD_SYMB_MAX, SEG_OFF);
#endif
#if VARIO_F_TIME
display_symbol(LCD_SEG_L2_COL1, SEG_OFF);
display_symbol(LCD_SEG_L2_COL0, SEG_OFF);
#endif
}
/* s8 hist_size(void) { */
/* if (svario.previous_end == -1) return 0; */
/* if (svario.previous_end == svario.previous_start) return VARIO_HIST_SIZE; */
/* return ((svario.previous_end-svario.previous_start)>0 ? VARIO_HIST_SIZE-svario.previous_end+svario.previous_start : svario.previous_start-svario.previous_end); */
/* } */
//
// Vario display update function. Theorethically called once per second.
// In practice, this also gets called on button presses, so careful if
// you rely on it for a 1Hz frequency.
//
void hist_add(s16 alt) {
if (svario.hist_count != VARIO_HIST_SIZE) svario.hist_count++;
extern void
display_vario( u8 line, u8 update )
{
static u8 _idone; // initialisation helper
static u8 _vbeat; // heartbeat
u32 pressure;
switch( update )
{
case DISPLAY_LINE_CLEAR:
stop_buzzer();
display_symbol( LCD_ICON_BEEPER1, SEG_OFF );
display_symbol( LCD_ICON_BEEPER2, SEG_OFF );
display_symbol( LCD_ICON_RECORD, SEG_OFF );
_display_l2_clean();
return;
case DISPLAY_LINE_UPDATE_FULL:
display_symbol( LCD_ICON_BEEPER1,
( G_vario.beep_mode ) ? SEG_ON : SEG_OFF );
display_symbol( LCD_ICON_BEEPER2,
( ( G_vario.beep_mode == VARIO_BEEPMODE_ASCENT_0 )
|| ( G_vario.beep_mode == VARIO_BEEPMODE_BOTH ))
? SEG_ON : SEG_OFF );
//
// fall through to partial update
//
case DISPLAY_LINE_UPDATE_PARTIAL:
break;
}
#if VARIO_F_TIME
// Update flight time regardless of whether we do have an altitude.
//
// Be careful to only update the time when a time update is active,
// ie, not because this refresh is due to a DOWN button press.
//
if ( display.flag.update_time )
{
G_vario.stats.f_time.ss++;
if ( G_vario.stats.f_time.ss > 59 )
{
G_vario.stats.f_time.ss = 0;
G_vario.stats.f_time.mm++;
if ( G_vario.stats.f_time.mm > 59 )
{
G_vario.stats.f_time.mm = 0;
G_vario.stats.f_time.hh++;
}
// Reset flight time after 19 hours, more will not fit on lcd !
if ( G_vario.stats.f_time.hh > 19 )
G_vario.stats.f_time.hh = 0;
}
}
#endif
//
// Partial or full update. Make sure pressure sensor is being sampled, ie,
// that line 1 is in altimeter mode.
//
if ( is_altitude_measurement() )
{
s16 diff;
if ( vario_p_read( &pressure ) )
{
// Happens during key presses, never mind.
return; // no data, wait for update
}
//
// If this is the very first time we are here, we have no previous
// pressure, handle that situation.
//
if ( !_idone )
{
diff = 0;
++_idone;
}
else
{
//
// Calculate difference in Pascal - we will need it anyway for the
// buzzer. Pressure decreases with altitude, ensure going lower is
// negative.
//
diff = G_vario.prev_pa - pressure;
#if VARIO_VZ
// update stats as we may want to see these after the flight.
if ( diff > G_vario.stats.vzmax ) G_vario.stats.vzmax = diff;
if ( diff < G_vario.stats.vzmin ) G_vario.stats.vzmin = diff;
#endif
#if VARIO_ALTMAX
// Peek at current altitude in altimeter data.
if ( G_vario.stats.altmax < sAlt.altitude )
G_vario.stats.altmax = sAlt.altitude;
#endif
}
_display_l2_clean();
// Pulse the vario heartbeat indicator.
++_vbeat;
display_symbol( LCD_ICON_RECORD, ( _vbeat & 1 ) ? SEG_ON : SEG_OFF );
// Now see what value to display.
switch( G_vario.view_mode )
{
case VARIO_VIEWMODE_ALT_M:
//
// convert the difference in Pa to a vertical velocity.
//
_display_signed( _pascal_to_vz( diff ), 1 );
break;
#if VARIO_ALT_PA
case VARIO_VIEWMODE_ALT_PA:
//
// display raw difference in Pascal.
//
_display_signed( diff, 0 );
break;
#endif
#if VARIO_PA
case VARIO_VIEWMODE_PA:
//
// display pressure as hhhh.pp (hPa and Pa)
//
_display_signed( pressure, 1 );
break;
#endif
#if VARIO_VZ
case VARIO_VIEWMODE_VZMAX:
display_symbol( LCD_SYMB_MAX, SEG_ON);
_display_signed( _pascal_to_vz( G_vario.stats.vzmax ), 1 );
break;
case VARIO_VIEWMODE_VZMIN:
display_symbol( LCD_SYMB_MAX, SEG_ON);
_display_signed( _pascal_to_vz( G_vario.stats.vzmin ), 1 );
break;
#endif
#if VARIO_ALTMAX
case VARIO_VIEWMODE_ALT_MAX:
display_symbol( LCD_SYMB_MAX, SEG_ON);
_display_signed( G_vario.stats.altmax, 0 );
break;
#endif
#if VARIO_F_TIME
case VARIO_VIEWMODE_F_TIME:
display_chars(LCD_SEG_L2_5_0, itoa(G_vario.stats.f_time.hh,2,0), SEG_ON);
display_chars(LCD_SEG_L2_3_0, itoa(G_vario.stats.f_time.mm,2,0), SEG_ON);
display_chars(LCD_SEG_L2_1_0, itoa(G_vario.stats.f_time.ss,2,0), SEG_ON);
display_symbol(LCD_SEG_L2_COL1, SEG_ON);
display_symbol(LCD_SEG_L2_COL0, SEG_ON);
break;
#endif
case VARIO_VIEWMODE_MAX:
break;
} // switch view mode
// If beeper is enabled, beep.
switch ( G_vario.beep_mode )
{
case VARIO_BEEPMODE_ASCENT_0:
if ( diff >= 0 ) chirp( diff );
break;
case VARIO_BEEPMODE_ASCENT_1:
if ( diff > 0 ) chirp( diff );
break;
case VARIO_BEEPMODE_BOTH:
if ( diff ) chirp( diff );
break;
case VARIO_BEEPMODE_OFF:
case VARIO_BEEPMODE_MAX:
break;
}
// update previous pressure measurement.
svario.hist_alts[svario.hist_pos] = alt;
svario.hist_pos = (svario.hist_pos+1)%VARIO_HIST_SIZE;
}
G_vario.prev_pa = pressure;
void reset_vario(void)
{
svario.state = VARIO_STOP;
svario.hist_pos = svario.hist_count = 0;
} // L1 is in altimeter mode
else
{
_display_l2_clean();
display_chars(LCD_SEG_L2_5_0, (u8*) " NOALT", SEG_ON);
_idone = 0; // avoid false peaks when re-enabling the altimeter
}
}
#endif /* CONFIG_VARIO */

27
logic/vario.h

@ -1,6 +1,8 @@
/*
Vario function for ez430 chronos watch.
Copyright (C) 2010 Marc Poulhiès <dkm@kataplop.net>
Altivario function for ez430 chronos watch.
Copyright (C) 2011, Marc Bongartz <mbong@free.fr>
Build environment Copyright (C) 2010 Marc Poulhi<E8>s <dkm@kataplop.net>
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
@ -54,27 +56,12 @@
#ifndef VARIO_H_
#define VARIO_H_
// menu functions
// menu function callbacks
extern void sx_vario(u8 line);
extern void mx_vario(u8 line);
extern void display_vario(u8 line, u8 update);
extern void reset_vario(void);
extern void vario_tick(void);
extern void update_vario(void);
extern u8 is_vario(void);
#define VARIO_STOP (0u)
#define VARIO_RUN (1u)
#define VARIO_HIST_SIZE 10
struct vario
{
u8 state;
u8 hist_alts[VARIO_HIST_SIZE];
u8 hist_count, hist_pos;
};
// external function to update the pressure value.
extern void vario_p_write(u32);
extern struct vario svario;
#endif

Loading…
Cancel
Save