From 239a8ee47b7a6bb4bb5aab4a429ee368f12b9613 Mon Sep 17 00:00:00 2001 From: HashakGik Date: Wed, 15 May 2019 19:56:23 +0200 Subject: [PATCH] Added accelerometer and pressure drivers for white PCB, and new modules. --- .gitignore | 8 + Makefile | 6 +- README.md | 22 + boot.c | 65 +- contrib/ChronosTool.py | 18 +- contrib/rtttl2bin.py | 2 +- drivers/adc12.c | 146 ++--- drivers/as.c | 231 +++++++ drivers/as.h | 104 ++++ drivers/battery.c | 82 +-- drivers/battery.h | 38 +- drivers/bmp_as.c | 352 +++++++++++ drivers/bmp_as.h | 182 ++++++ drivers/bmp_ps.c | 247 ++++++++ drivers/bmp_ps.h | 104 ++++ drivers/buzzer.c | 118 ++-- drivers/buzzer.h | 28 +- drivers/display.c | 768 ++++++++++++----------- drivers/display.h | 464 +++++++------- drivers/dsp.c | 16 +- drivers/infomem.c | 1168 +++++++++++++++++------------------ drivers/infomem.h | 12 +- drivers/lpm.c | 44 +- drivers/lpm.h | 28 +- drivers/pmm.c | 46 +- drivers/pmm.h | 24 +- drivers/ports.c | 192 +++--- drivers/ports.h | 116 ++-- drivers/ps.c | 446 +++++++++++++ drivers/ps.h | 103 +++ drivers/radio.c | 94 +-- drivers/rf1a.c | 178 +++--- drivers/rtc_dst.c | 244 ++++---- drivers/rtc_dst.h | 34 +- drivers/rtca.c | 386 ++++++------ drivers/rtca.h | 66 +- drivers/temperature.c | 162 ++--- drivers/temperature.h | 34 +- drivers/timer.c | 304 ++++----- drivers/timer.h | 120 ++-- drivers/utils.h | 34 +- drivers/vti_as.c | 677 ++++++++++---------- drivers/vti_as.h | 117 +--- drivers/vti_ps.c | 721 --------------------- drivers/vti_ps.h | 108 ---- drivers/wdt.c | 36 +- drivers/wdt.h | 28 +- menu.c | 194 +++--- menu.h | 60 +- messagebus.c | 82 +-- messagebus.h | 62 +- modules/accelerometer.c | 499 --------------- modules/accelerometer.cfg | 4 - modules/accelerometer_b.c | 480 ++++++++++++++ modules/accelerometer_b.cfg | 5 + modules/accelerometer_w.c | 182 ++++++ modules/accelerometer_w.cfg | 5 + modules/alarm.c | 244 ++++---- modules/alarm.cfg | 4 +- modules/altimeter.c | 80 +++ modules/altimeter.cfg | 13 + modules/battery.c | 91 ++- modules/battery.cfg | 6 +- modules/boil.c | 150 +++++ modules/boil.cfg | 13 + modules/buzztest.c | 109 ++-- modules/buzztest.cfg | 4 +- modules/clock.c | 398 ++++++------ modules/clock.cfg | 10 +- modules/crickets.c | 109 ++++ modules/crickets.cfg | 12 + modules/hashutils.c | 379 ++++++------ modules/hashutils.h | 22 +- modules/hello.c | 66 ++ modules/hello.cfg | 5 + modules/music.c | 52 +- modules/music.cfg | 5 +- modules/otp.c | 288 ++++----- modules/otp.cfg | 10 +- modules/otp.h | 9 +- modules/reset.c | 72 +-- modules/reset.cfg | 6 +- modules/soundspeed.c | 139 +++++ modules/soundspeed.cfg | 13 + modules/steps.c | 82 +++ modules/steps.cfg | 5 + modules/stopwatch.c | 292 +++++---- modules/stopwatch.cfg | 4 +- modules/temperature.c | 161 ++--- modules/temperature.cfg | 4 +- modules/tide.c | 395 ++++++------ modules/tide.cfg | 4 +- openchronos.c | 117 ++-- openchronos.h | 17 +- tools/config.py | 53 +- 95 files changed, 7685 insertions(+), 5854 deletions(-) create mode 100644 drivers/as.c create mode 100644 drivers/as.h create mode 100644 drivers/bmp_as.c create mode 100644 drivers/bmp_as.h create mode 100644 drivers/bmp_ps.c create mode 100644 drivers/bmp_ps.h create mode 100644 drivers/ps.c create mode 100644 drivers/ps.h delete mode 100644 drivers/vti_ps.c delete mode 100644 drivers/vti_ps.h delete mode 100644 modules/accelerometer.c delete mode 100644 modules/accelerometer.cfg create mode 100644 modules/accelerometer_b.c create mode 100644 modules/accelerometer_b.cfg create mode 100644 modules/accelerometer_w.c create mode 100644 modules/accelerometer_w.cfg create mode 100644 modules/altimeter.c create mode 100644 modules/altimeter.cfg create mode 100644 modules/boil.c create mode 100644 modules/boil.cfg create mode 100644 modules/crickets.c create mode 100644 modules/crickets.cfg create mode 100644 modules/hello.c create mode 100644 modules/hello.cfg create mode 100644 modules/soundspeed.c create mode 100644 modules/soundspeed.cfg create mode 100644 modules/steps.c create mode 100644 modules/steps.cfg diff --git a/.gitignore b/.gitignore index 60026f3..435bb7d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,11 @@ +### emacs backup files +*~ +contrib/*~ +drivers/*~ +modules/*~ +toolchains/*~ +tools/*~ + ### Temp files ### nohup.out *.[oa] diff --git a/Makefile b/Makefile index 7258070..4ecd42c 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,6 @@ +# Edit this with your compiler's path: +MSP430_TI = /root/ti/msp430-gcc + SUBDIRS = drivers modules include Common.mk @@ -56,9 +59,10 @@ $(OBJS): openchronos.cflags # # Top rules +# Strangely enough libm must be linked last... openchronos.elf: $(OBJS) @echo "\n>> Building $@ as target $(TARGET)" - @$(CC) $(CFLAGS) $(LDFLAGS) $(INCLUDES) -o $@ $+ + @$(CC) $(CFLAGS) $(LDFLAGS) $(INCLUDES) -o $@ $+ -lm openchronos.txt: openchronos.elf $(PYTHON) tools/memory.py -i $< -o $@ diff --git a/README.md b/README.md index b1800a3..783f3bc 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,25 @@ +OpenChronos-ng-elf fork +======================= + +Added features +-------------- + +* Added support for BMA250 accelerometer and BMP85 pressure and temperature sensor (packed in the white PCB eZ430-Chronos) +* Added Black/White PCB dependencies in config.py +* Added new modules +* Music module now plays a shorter tune (Nokia tune instead of Super Mario Bros. theme). + +New modules +----------- + +* Altimeter module for white PCB +* Accelerometer module for white PCB +* Boiling point calculator for white PCB +* Cricket's chirp calculator (any PCB) +* Scrolling hello world (any PCB) +* Speed of sound calculator for white PCB +* Step counter calculator for white PCB. + GENERAL INFORMATION =================== diff --git a/boot.c b/boot.c index 9a55975..6db9418 100644 --- a/boot.c +++ b/boot.c @@ -46,7 +46,7 @@ #define PORTS_BTN_DOWN_PIN (BIT0) -inline void initialize_aclk() +void initialize_aclk() { /* Select XIN, XOUT on P5.0 and P5.1 */ P5SEL |= 0x03; @@ -64,7 +64,7 @@ inline void initialize_aclk() UCSCTL4 = SELA__XT1CLK | SELS__DCOCLKDIV | SELM__DCOCLKDIV; } -inline void initialize_cpu_12mhz() +void initialize_cpu_12mhz() { /* Disable the FLL control loop */ _BIS_SR(SCG0); @@ -76,26 +76,26 @@ inline void initialize_cpu_12mhz() UCSCTL1 = DCORSEL_5; /* Set DCO Multiplier */ - UCSCTL2 = FLLD_1 + 0x16E; // (32768 * 0x16e) almost 12 mhz + UCSCTL2 = FLLD_1 + 0x16E; // (32768 * 0x16e) almost 12 mhz _BIC_SR(SCG0); /* Worst-case settling time for the DCO when the DCO range bits have been - changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx - UG for optimization. - 32 x 32 x 12 MHz / 32,768 Hz = 250000 = MCLK cycles for DCO to settle */ + changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx + UG for optimization. + 32 x 32 x 12 MHz / 32,768 Hz = 250000 = MCLK cycles for DCO to settle */ __delay_cycles(375000); /* Loop until XT1 & DCO stabilizes, use do-while to insure that - body is executed at least once */ + body is executed at least once */ do { - UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + XT1HFOFFG + DCOFFG); + UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + XT1HFOFFG + DCOFFG); - /* Clear fault flags */ - SFRIFG1 &= ~OFIFG; + /* Clear fault flags */ + SFRIFG1 &= ~OFIFG; } while ((SFRIFG1 & OFIFG)); } -inline void initialize_buttons() +void initialize_buttons() { /* Set button ports to input */ P2DIR &= ~ALL_BUTTONS; @@ -105,7 +105,7 @@ inline void initialize_buttons() P2REN |= ALL_BUTTONS; } -inline void initialize_lcd() +void initialize_lcd() { /* clear entire display memory */ LCDBMEMCTL |= LCDCLRBM + LCDCLRM; @@ -120,11 +120,11 @@ inline void initialize_lcd() /* LCD_FREQ = ACLK/8/8 = 512Hz */ /* Frame frequency = 512Hz/2/4 = 64Hz, LCD mux 4, LCD on */ LCDBCTL0 = (LCDDIV0 + LCDDIV1 + LCDDIV2) - | (LCDPRE0 + LCDPRE1) | LCD4MUX | LCDON; + | (LCDPRE0 + LCDPRE1) | LCD4MUX | LCDON; /* LCB_BLK_FREQ = ACLK/8/2048 = 2Hz */ LCDBBLKCTL = LCDBLKPRE1 | LCDBLKDIV0 | LCDBLKDIV1 - | LCDBLKDIV2 | LCDBLKMOD0; + | LCDBLKDIV2 | LCDBLKMOD0; /* I/O to COM outputs */ P5SEL |= (BIT5 | BIT6 | BIT7); @@ -143,7 +143,7 @@ inline void initialize_lcd() #endif } -inline void jump_to_rfbsl() +void jump_to_rfbsl() { /* clear display memory (useful to know if rfbsl failed) */ LCDBMEMCTL |= LCDCLRBM + LCDCLRM; @@ -154,7 +154,7 @@ inline void jump_to_rfbsl() /* put bootmenu in the crt_0042 section which is executed before main */ -__attribute__((naked, section(".crt_0042"), used)) +__attribute__ ((naked, section(".crt_0042"), used)) static void crt_0042(void) { wdt_stop(); @@ -164,9 +164,9 @@ static void crt_0042(void) /* Set global high power request enable */ { - PMMCTL0_H = 0xA5; - PMMCTL0_L |= PMMHPMRE; - PMMCTL0_H = 0x00; + PMMCTL0_H = 0xA5; + PMMCTL0_L |= PMMHPMRE; + PMMCTL0_H = 0x00; } /* Enable 32kHz ACLK */ @@ -182,18 +182,18 @@ static void crt_0042(void) initialize_lcd(); /* Write 'boot' to the screen without using display functions */ - LCDM2 = 199; /* 'b' */ - LCDM3 = 198; /* 'o' */ - LCDM4 = 198; /* 'o' */ - LCDM6 = 135; /* 't' */ + LCDM2 = 199; /* 'b' */ + LCDM3 = 198; /* 'o' */ + LCDM4 = 198; /* 'o' */ + LCDM6 = 135; /* 't' */ /* configure watchdog interrupt timer, used for polling buttons */ { - /* ACLK timer source, 250ms timer mode, resume watchdog */ - WDTCTL = WDT_ADLY_250; + /* ACLK timer source, 250ms timer mode, resume watchdog */ + WDTCTL = WDT_ADLY_250; - /* Enable watchdog timer interrupts */ - SFRIE1 |= WDTIE; + /* Enable watchdog timer interrupts */ + SFRIE1 |= WDTIE; } /* Enable global interrupts */ @@ -201,11 +201,11 @@ static void crt_0042(void) /* loop if no button is pressed, enter RFBSL if backlight is pressed */ do { - _BIS_SR(LPM3_bits | GIE); - __no_operation(); + _BIS_SR(LPM3_bits | GIE); + __no_operation(); - if ((P2IN & ALL_BUTTONS) == PORTS_BTN_DOWN_PIN) - jump_to_rfbsl(); + if ((P2IN & ALL_BUTTONS) == PORTS_BTN_DOWN_PIN) + jump_to_rfbsl(); } while ((P2IN & ALL_BUTTONS) == 0); @@ -213,10 +213,9 @@ static void crt_0042(void) __disable_interrupt(); } -__attribute__((interrupt(WDT_VECTOR))) +__attribute__ ((interrupt(WDT_VECTOR))) void WDT_ISR(void) { /* exit from LPM3 after interrupt */ _BIC_SR_IRQ(LPM3_bits); } - diff --git a/contrib/ChronosTool.py b/contrib/ChronosTool.py index ce38d1d..f322d1f 100755 --- a/contrib/ChronosTool.py +++ b/contrib/ChronosTool.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # -*- coding: utf-8 -*- ################################################################################################### # ChronosTool.py @@ -245,7 +245,7 @@ def __del__( self ): self.device.close def send( self, cmd ): - self.device.write( cmd.tostr() ) + self.device.write( cmd.tobytes() ) time.sleep( 0.015 ) if opt.verbose: print >> sys.stderr, 'SENT:', cmd.tohex() @@ -406,7 +406,7 @@ def spl_sync( self, dt=[], celsius=0, meters=0 ): time.sleep(2) if not dt: dt = datetime.datetime.now() - print "Syncing Time %s, Temp %s C, and altitude %s m)" % (str(dt), str(celsius), str(meters)) + print("Syncing Time %s, Temp %s C, and altitude %s m)") % (str(dt), str(celsius), str(meters)) payload = bytearray( 0x13 ) payload[0x00] = 0x03 @@ -427,7 +427,7 @@ def spl_sync( self, dt=[], celsius=0, meters=0 ): self.sendcmd( 0x31, payload ) #BM_SYNC_SendCommand time.sleep( 2 ) self.spl_stop() - print "Synced!" + print("Synced!") def transmitburst( self, data ): self.wbsl_start() @@ -649,17 +649,17 @@ def wbsl_download( self, txtdata ): 30 1D q""") data = CBMdata() - print "Reading firmware file" + print("Reading firmware file") data.importtxt( txtdata ) raw_input("Hit enter to start update process. (or Ctrl+C to exit)") - print "Ready to update. Set your watch in rfbsl \"open\" mode." + print("Ready to update. Set your watch in rfbsl \"open\" mode.") self.transmitburst( updater ) - print "Sending new firmware.." + print("Sending new firmware..") self.transmitburst( data ) time.sleep( 1 ) - print "Done!" + print("Done!") ################################################################################################### # main @@ -747,7 +747,7 @@ def wbsl_download( self, txtdata ): while True: data = bm.spl_getaccel() if data[0]: - print str( data[1] ) + " " + str( data[2] ) + " " + str( data[3] ) + print(str( data[1] ) + " " + str( data[2] ) + " " + str( data[3] )) else: print >> sys.stderr, "ERROR: invalid command:", command sys.exit( 4 ) diff --git a/contrib/rtttl2bin.py b/contrib/rtttl2bin.py index ed1579b..4c31916 100644 --- a/contrib/rtttl2bin.py +++ b/contrib/rtttl2bin.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3.2 +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Copyright (C) 2012 Aljaž Srebrnič diff --git a/drivers/adc12.c b/drivers/adc12.c index a75c976..2acbe3c 100644 --- a/drivers/adc12.c +++ b/drivers/adc12.c @@ -73,48 +73,48 @@ uint8_t adc12_data_ready; // ************************************************************************************************* uint16_t adc12_single_conversion(uint16_t ref, uint16_t sht, uint16_t channel) { - // Initialize the shared reference module - REFCTL0 |= REFMSTR + ref + REFON; // Enable internal reference (1.5V or 2.5V) + // Initialize the shared reference module + REFCTL0 |= REFMSTR + ref + REFON; // Enable internal reference (1.5V or 2.5V) - // Initialize ADC12_A - ADC12CTL0 = sht + ADC12ON; // Set sample time - ADC12CTL1 = ADC12SHP; // Enable sample timer - ADC12MCTL0 = ADC12SREF_1 + channel; // ADC input channel - ADC12IE = 0x001; // ADC_IFG upon conv result-ADCMEMO + // Initialize ADC12_A + ADC12CTL0 = sht + ADC12ON; // Set sample time + ADC12CTL1 = ADC12SHP; // Enable sample timer + ADC12MCTL0 = ADC12SREF_1 + channel; // ADC input channel + ADC12IE = 0x001; // ADC_IFG upon conv result-ADCMEMO - // Wait 2 ticks (66us) to allow internal reference to settle - timer0_delay(66,LPM3_bits); + // Wait 2 ticks (66us) to allow internal reference to settle + timer0_delay(66,LPM3_bits); - // Start ADC12 - ADC12CTL0 |= ADC12ENC; + // Start ADC12 + ADC12CTL0 |= ADC12ENC; - // Clear data ready flag - adc12_data_ready = 0; + // Clear data ready flag + adc12_data_ready = 0; - // Sampling and conversion start - ADC12CTL0 |= ADC12SC; + // Sampling and conversion start + ADC12CTL0 |= ADC12SC; - // Wait until ADC12 has finished - timer0_delay(170, LPM3_bits); + // Wait until ADC12 has finished + timer0_delay(170, LPM3_bits); - uint8_t loops = 0; + uint8_t loops = 0; - //We were going away and the watchdog was tripping - this should reduce the instances of that. - while (!adc12_data_ready && loops++ < 30) { - timer0_delay(66, LPM3_bits); - } + //We were going away and the watchdog was tripping - this should reduce the instances of that. + while (!adc12_data_ready && loops++ < 30) { + timer0_delay(66, LPM3_bits); + } - // Shut down ADC12 - ADC12CTL0 &= ~(ADC12ENC | ADC12SC | sht); - ADC12CTL0 &= ~ADC12ON; + // Shut down ADC12 + ADC12CTL0 &= ~(ADC12ENC | ADC12SC | sht); + ADC12CTL0 &= ~ADC12ON; - // Shut down reference voltage - REFCTL0 &= ~(REFMSTR + ref + REFON); + // Shut down reference voltage + REFCTL0 &= ~(REFMSTR + ref + REFON); - ADC12IE = 0; + ADC12IE = 0; - // Return ADC result - return (adc12_result); + // Return ADC result + return (adc12_result); } @@ -130,67 +130,67 @@ uint16_t adc12_single_conversion(uint16_t ref, uint16_t sht, uint16_t channel) __attribute__((interrupt(ADC12_VECTOR))) void ADC12ISR(void) { - switch (__even_in_range(ADC12IV, 34)) { - case 0: - break; // Vector 0: No interrupt + switch (__even_in_range(ADC12IV, 34)) { + case 0: + break; // Vector 0: No interrupt - case 2: - break; // Vector 2: ADC overflow + case 2: + break; // Vector 2: ADC overflow - case 4: - break; // Vector 4: ADC timing overflow + case 4: + break; // Vector 4: ADC timing overflow - case 6: // Vector 6: ADC12IFG0 - adc12_result = ADC12MEM0; // Move results, IFG is cleared - adc12_data_ready = 1; - _BIC_SR_IRQ(LPM3_bits); // Exit active CPU - break; + case 6: // Vector 6: ADC12IFG0 + adc12_result = ADC12MEM0; // Move results, IFG is cleared + adc12_data_ready = 1; + _BIC_SR_IRQ(LPM3_bits); // Exit active CPU + break; - case 8: - break; // Vector 8: ADC12IFG1 + case 8: + break; // Vector 8: ADC12IFG1 - case 10: - break; // Vector 10: ADC12IFG2 + case 10: + break; // Vector 10: ADC12IFG2 - case 12: - break; // Vector 12: ADC12IFG3 + case 12: + break; // Vector 12: ADC12IFG3 - case 14: - break; // Vector 14: ADC12IFG4 + case 14: + break; // Vector 14: ADC12IFG4 - case 16: - break; // Vector 16: ADC12IFG5 + case 16: + break; // Vector 16: ADC12IFG5 - case 18: - break; // Vector 18: ADC12IFG6 + case 18: + break; // Vector 18: ADC12IFG6 - case 20: - break; // Vector 20: ADC12IFG7 + case 20: + break; // Vector 20: ADC12IFG7 - case 22: - break; // Vector 22: ADC12IFG8 + case 22: + break; // Vector 22: ADC12IFG8 - case 24: - break; // Vector 24: ADC12IFG9 + case 24: + break; // Vector 24: ADC12IFG9 - case 26: - break; // Vector 26: ADC12IFG10 + case 26: + break; // Vector 26: ADC12IFG10 - case 28: - break; // Vector 28: ADC12IFG11 + case 28: + break; // Vector 28: ADC12IFG11 - case 30: - break; // Vector 30: ADC12IFG12 + case 30: + break; // Vector 30: ADC12IFG12 - case 32: - break; // Vector 32: ADC12IFG13 + case 32: + break; // Vector 32: ADC12IFG13 - case 34: - break; // Vector 34: ADC12IFG14 + case 34: + break; // Vector 34: ADC12IFG14 - default: - break; - } + default: + break; + } } diff --git a/drivers/as.c b/drivers/as.c new file mode 100644 index 0000000..faf91e5 --- /dev/null +++ b/drivers/as.c @@ -0,0 +1,231 @@ +// ************************************************************************************************* +// +// Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the +// distribution. +// +// Neither the name of Texas Instruments Incorporated nor the names of +// its contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ************************************************************************************************* +// acceleration sensor driver functions +// ************************************************************************************************* + + +// ************************************************************************************************* +// Include section + +// system +//#include "project.h" + +// driver +#include "openchronos.h" +#include "as.h" +#include "timer.h" + + +// ************************************************************************************************* +// Prototypes section + +// ************************************************************************************************* +// Defines section + +// ************************************************************************************************* +// Global Variable section + +// Global flag for proper acceleration sensor operation + +// ************************************************************************************************* +// Extern section + + + + + + + + +// ************************************************************************************************* +// @fn as_init +// @brief Setup acceleration sensor connection, do not power up yet +// @param none +// @return none +// ************************************************************************************************* +void as_init(void) +{ + // Deactivate connection to acceleration sensor + AS_PWR_OUT &= ~AS_PWR_PIN; // Power off + AS_INT_OUT &= ~AS_INT_PIN; // Pin to low to avoid floating pins + AS_SPI_OUT &= ~(AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN); // Pin to low to avoid floating pins + AS_CSN_OUT &= ~AS_CSN_PIN; // Pin to low to avoid floating pins + AS_INT_DIR |= AS_INT_PIN; // Pin to output to avoid floating pins + AS_SPI_DIR |= AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN; // Pin to output to avoid floating pins + AS_CSN_DIR |= AS_CSN_PIN; // Pin to output to avoid floating pins + AS_PWR_DIR |= AS_PWR_PIN; // Power pin to output direction +} + +// ************************************************************************************************* +// @fn as_start +// @brief Power-up and initialize acceleration sensor +// @param none +// @return none +// ************************************************************************************************* +void as_start(void) +{ + // Initialize interrupt pin for data read out from acceleration sensor + AS_INT_IES &= ~AS_INT_PIN; // Interrupt on rising edge + + // Enable interrupt + AS_INT_DIR &= ~AS_INT_PIN; // Switch INT pin to input + AS_SPI_DIR &= ~AS_SDI_PIN; // Switch SDI pin to input + AS_SPI_REN |= AS_SDI_PIN; // Pulldown on SDI pin + AS_SPI_SEL |= AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN; // Port pins to SDO, SDI and SCK function + AS_CSN_OUT |= AS_CSN_PIN; // Deselect acceleration sensor + AS_PWR_OUT |= AS_PWR_PIN; // Power on active high + + // Delay of >5ms required between switching on power and configuring sensor + timer0_delay(10, LPM3_bits); + + // Initialize interrupt pin for data read out from acceleration sensor + AS_INT_IFG &= ~AS_INT_PIN; // Reset flag + AS_INT_IE |= AS_INT_PIN; // Enable interrupt +} + +// ************************************************************************************************* +// @fn as_stop +// @brief Power down acceleration sensor +// @param none +// @return none +// ************************************************************************************************* +void as_stop(void) +{ + // Disable interrupt + AS_INT_IE &= ~AS_INT_PIN; // Disable interrupt + + // Power-down sensor + AS_PWR_OUT &= ~AS_PWR_PIN; // Power off + AS_INT_OUT &= ~AS_INT_PIN; // Pin to low to avoid floating pins + AS_SPI_OUT &= ~(AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN); // Pins to low to avoid floating pins + AS_SPI_SEL &= ~(AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN); // Port pins to I/O function + AS_CSN_OUT &= ~AS_CSN_PIN; // Pin to low to avoid floating pins + AS_INT_DIR |= AS_INT_PIN; // Pin to output to avoid floating pins + AS_SPI_DIR |= AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN; // Pins to output to avoid floating pins + AS_CSN_DIR |= AS_CSN_PIN; // Pin to output to avoid floating pins +} + +// ************************************************************************************************* +// @fn as_read_register +// @brief Read a byte from the acceleration sensor +// @param uint8_t bAddress Register address +// @return uint8_t bResult Register content +// If the returned value is 0, +// there was an error. +// ************************************************************************************************* +uint8_t as_read_register(uint8_t bAddress) +{ + uint8_t bResult; + uint16_t timeout; + + AS_SPI_REN &= ~AS_SDI_PIN; // Pulldown on SDI pin not required + AS_CSN_OUT &= ~AS_CSN_PIN; // Select acceleration sensor + + bResult = AS_RX_BUFFER; // Read RX buffer just to clear + // interrupt flag + + AS_TX_BUFFER = bAddress; // Write address to TX buffer + + timeout = AS_SPI_TIMEOUT; + while (!(AS_IRQ_REG & AS_RX_IFG) && (--timeout > 0)); // Wait until new data was written into + // RX buffer + if (timeout == 0) + { + return (0); + } + bResult = AS_RX_BUFFER; // Read RX buffer just to clear + // interrupt flag + + AS_TX_BUFFER = 0; // Write dummy data to TX buffer + + timeout = AS_SPI_TIMEOUT; + while (!(AS_IRQ_REG & AS_RX_IFG) && (--timeout > 0)); // Wait until new data was written into + // RX buffer + if (timeout == 0) + { + return (0); + } + bResult = AS_RX_BUFFER; // Read RX buffer + + AS_CSN_OUT |= AS_CSN_PIN; // Deselect acceleration sensor + AS_SPI_REN |= AS_SDI_PIN; // Pulldown on SDI pin required again + + // Return new data from RX buffer + return bResult; +} + +// ************************************************************************************************* +// @fn as_write_register +// @brief Write a byte to the acceleration sensor +// @param uint8_t bAddress Register address +// uint8_t bData Data to write +// @return uint8_t 0 or bResult Register content. +// If the returned value is 0, +// there was an error. +// ************************************************************************************************* +uint8_t as_write_register(uint8_t bAddress, uint8_t bData) +{ + uint8_t bResult; + uint16_t timeout; + + AS_SPI_REN &= ~AS_SDI_PIN; // Pulldown on SDI pin not required + AS_CSN_OUT &= ~AS_CSN_PIN; // Select acceleration sensor + + bResult = AS_RX_BUFFER; // Read RX buffer just to clear + // interrupt flag + + AS_TX_BUFFER = bAddress; // Write address to TX buffer + + timeout = AS_SPI_TIMEOUT; + while (!(AS_IRQ_REG & AS_RX_IFG) && (--timeout > 0)); // Wait until new data was written into + // RX buffer + + bResult = AS_RX_BUFFER; // Read RX buffer just to clear + // interrupt flag + + AS_TX_BUFFER = bData; // Write data to TX buffer + + + timeout = AS_SPI_TIMEOUT; + while (!(AS_IRQ_REG & AS_RX_IFG) && (--timeout > 0)); // Wait until new data was written into + // RX buffer + + bResult = AS_RX_BUFFER; // Read RX buffer + + AS_CSN_OUT |= AS_CSN_PIN; // Deselect acceleration sensor + AS_SPI_REN |= AS_SDI_PIN; // Pulldown on SDI pin required again + + return bResult; +} diff --git a/drivers/as.h b/drivers/as.h new file mode 100644 index 0000000..a2979b6 --- /dev/null +++ b/drivers/as.h @@ -0,0 +1,104 @@ +// ************************************************************************************************* +// +// Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the +// distribution. +// +// Neither the name of Texas Instruments Incorporated nor the names of +// its contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ************************************************************************************************* + +#ifndef AS_H_ +#define AS_H_ + +// ************************************************************************************************* +// Include section + +// ************************************************************************************************* +// Prototypes section + +// ************************************************************************************************* +// Defines section + +// Disconnect power supply for acceleration sensor when not used +#define AS_DISCONNECT + +// Port and pin resource for SPI interface to acceleration sensor +// SDO=MOSI=P1.6, SDI=MISO=P1.5, SCK=P1.7 +#define AS_SPI_IN (P1IN) +#define AS_SPI_OUT (P1OUT) +#define AS_SPI_DIR (P1DIR) +#define AS_SPI_SEL (P1SEL) +#define AS_SPI_REN (P1REN) +#define AS_SDO_PIN (BIT6) +#define AS_SDI_PIN (BIT5) +#define AS_SCK_PIN (BIT7) + +// CSN=PJ.1 +#define AS_CSN_OUT (PJOUT) +#define AS_CSN_DIR (PJDIR) +#define AS_CSN_PIN (BIT1) + +#define AS_TX_BUFFER (UCA0TXBUF) +#define AS_RX_BUFFER (UCA0RXBUF) +#define AS_TX_IFG (UCTXIFG) +#define AS_RX_IFG (UCRXIFG) +#define AS_IRQ_REG (UCA0IFG) +#define AS_SPI_CTL0 (UCA0CTL0) +#define AS_SPI_CTL1 (UCA0CTL1) +#define AS_SPI_BR0 (UCA0BR0) +#define AS_SPI_BR1 (UCA0BR1) + +// Port and pin resource for power-up of acceleration sensor, VDD=PJ.0 +#define AS_PWR_OUT (PJOUT) +#define AS_PWR_DIR (PJDIR) +#define AS_PWR_PIN (BIT0) + +// Port, pin and interrupt resource for interrupt from acceleration sensor, CMA_INT=P2.5 +#define AS_INT_IN (P2IN) +#define AS_INT_OUT (P2OUT) +#define AS_INT_DIR (P2DIR) +#define AS_INT_IE (P2IE) +#define AS_INT_IES (P2IES) +#define AS_INT_IFG (P2IFG) +#define AS_INT_PIN (BIT5) + +// SPI timeout to detect sensor failure +#define AS_SPI_TIMEOUT (1000u) + +// ************************************************************************************************* +// Global Variable section + +volatile uint8_t as_last_interrupt; + +// ************************************************************************************************* +// Extern section + + + +#endif /*AS_H_*/ diff --git a/drivers/battery.c b/drivers/battery.c index 8db836f..be887bd 100644 --- a/drivers/battery.c +++ b/drivers/battery.c @@ -1,25 +1,25 @@ /** - battery.c: battery voltage measurement driver + battery.c: battery voltage measurement driver - Copyright (C) 2012 Matthew Excell - Copyright (C) 2012 Angelo Arrifano + Copyright (C) 2012 Matthew Excell + Copyright (C) 2012 Angelo Arrifano - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ /*************************************************************************** @@ -66,44 +66,44 @@ void battery_init(void) { - /* Start with battery voltage estimate of full and avoid low - battery warnings until the voltage estimate converges. */ - battery_info.voltage = BATTERY_FULL_THRESHOLD; + /* Start with battery voltage estimate of full and avoid low + battery warnings until the voltage estimate converges. */ + battery_info.voltage = BATTERY_FULL_THRESHOLD; } void battery_measurement(void) { - /* Convert external battery voltage (ADC12INCH_11=AVCC-AVSS/2) - voltage = adc12_single_conversion(REFVSEL_2, ADC12SHT0_10, - ADC12SSEL_0, ADC12SREF_1, ADC12INCH_11, - ADC12_BATT_CONVERSION_TIME_USEC); */ - uint16_t voltage = adc12_single_conversion(REFVSEL_1, - ADC12SHT0_10, ADC12INCH_11); + /* Convert external battery voltage (ADC12INCH_11=AVCC-AVSS/2) + voltage = adc12_single_conversion(REFVSEL_2, ADC12SHT0_10, + ADC12SSEL_0, ADC12SREF_1, ADC12INCH_11, + ADC12_BATT_CONVERSION_TIME_USEC); */ + uint16_t voltage = adc12_single_conversion(REFVSEL_1, + ADC12SHT0_10, ADC12INCH_11); - /* Convert ADC value to "x.xx V" - Ideally we have A11=0->AVCC=0V ... A11=4095(2^12-1)->AVCC=4V - --> (A11/4095)*4V=AVCC --> AVCC=(A11*4)/4095 */ - voltage = (voltage << 2) / 41; + /* Convert ADC value to "x.xx V" + Ideally we have A11=0->AVCC=0V ... A11=4095(2^12-1)->AVCC=4V + --> (A11/4095)*4V=AVCC --> AVCC=(A11*4)/4095 */ + voltage = (voltage << 2) / 41; - /* Correct measured voltage with calibration value */ - voltage += battery_info.offset; + /* Correct measured voltage with calibration value */ + voltage += battery_info.offset; - /* Discard values that are clearly outside the measurement range */ - if (voltage > BATTERY_HIGH_THRESHOLD) - voltage = battery_info.voltage; + /* Discard values that are clearly outside the measurement range */ + if (voltage > BATTERY_HIGH_THRESHOLD) + voltage = battery_info.voltage; #ifndef CONFIG_BATTERY_DISABLE_FILTER - /* Filter battery voltage */ - battery_info.voltage = ((voltage << 1) - + (battery_info.voltage << 3)) / 10; + /* Filter battery voltage */ + battery_info.voltage = ((voltage << 1) + + (battery_info.voltage << 3)) / 10; #else - /* Get it raw instead for testing */ - battery_info.voltage = voltage; + /* Get it raw instead for testing */ + battery_info.voltage = voltage; #endif - /* Display blinking battery symbol if low */ - if (battery_info.voltage < BATTERY_LOW_THRESHOLD) - display_symbol(0, LCD_SYMB_BATTERY, SEG_ON | BLINK_ON); + /* Display blinking battery symbol if low */ + if (battery_info.voltage < BATTERY_LOW_THRESHOLD) + display_symbol(0, LCD_SYMB_BATTERY, SEG_ON | BLINK_ON); } diff --git a/drivers/battery.h b/drivers/battery.h index a59c1fb..fdf6f64 100644 --- a/drivers/battery.h +++ b/drivers/battery.h @@ -1,25 +1,25 @@ /** - battery.h: battery voltage measurement driver + battery.h: battery voltage measurement driver - Copyright (C) 2012 Matthew Excell - Copyright (C) 2012 Angelo Arrifano + Copyright (C) 2012 Matthew Excell + Copyright (C) 2012 Angelo Arrifano - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ /*************************************************************************** @@ -79,11 +79,11 @@ void battery_measurement(void); #define BATTERY_EMPTY_THRESHOLD (220u) struct { - /* Battery voltage */ - uint16_t voltage; + /* Battery voltage */ + uint16_t voltage; - /* Battery voltage offset */ - int16_t offset; + /* Battery voltage offset */ + int16_t offset; } battery_info; #endif /* __BATTERY_H__ */ diff --git a/drivers/bmp_as.c b/drivers/bmp_as.c new file mode 100644 index 0000000..8d8a223 --- /dev/null +++ b/drivers/bmp_as.c @@ -0,0 +1,352 @@ +// ************************************************************************************************* +// +// Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the +// distribution. +// +// Neither the name of Texas Instruments Incorporated nor the names of +// its contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ************************************************************************************************* +// Bosch BMA250 acceleration sensor driver functions +// ************************************************************************************************* + +// For advanced functions see datasheet: http://www1.futureelectronics.com/doc/BOSCH/BMA250-0273141121.pdf + +// ************************************************************************************************* +// Include section + +// system +#include +#include "openchronos.h" + +// driver +#include "bmp_as.h" +#include "as.h" +#include "timer.h" +#include "display.h" + + +// ************************************************************************************************* +// Prototypes section + +// ************************************************************************************************* +// Defines section + +// ================================================================================================= +// BMA250 acceleration sensor configuration +// ================================================================================================= +// DCO frequency division factor determining speed of the acceleration sensor SPI interface +// Speed in Hz = 12MHz / AS_BR_DIVIDER (max. 10MHz) +#define BMP_AS_BR_DIVIDER (2u) + +// ************************************************************************************************* +// Global Variable section + +// ************************************************************************************************* +// Extern section + + +// ************************************************************************************************* +// @fn bmp_as_start +// @brief Power-up and initialize acceleration sensor +// @param none +// @return none +// ************************************************************************************************* +void bmp_as_start(uint8_t bGRange, uint8_t bBwd, uint8_t bSleep, uint8_t filtering) +{ + // Initialize SPI interface to acceleration sensor + AS_SPI_CTL0 |= UCSYNC | UCMST | UCMSB // SPI master, 8 data bits, MSB first, + | UCCKPH; // clock idle low, data output on falling edge + AS_SPI_CTL1 |= UCSSEL1; // SMCLK as clock source + AS_SPI_BR0 = BMP_AS_BR_DIVIDER; // Low byte of division factor for baud rate + AS_SPI_BR1 = 0x00; // High byte of division factor for baud rate + AS_SPI_CTL1 &= ~UCSWRST; // Start SPI hardware + + // Configure interface pins + as_start(); + + // write sensor configuration + bmp_as_write_register(BMP_GRANGE, bGRange); // Set measurement range + bmp_as_write_register(BMP_BWD, bBwd); // Set filter bandwidth + bmp_as_write_register(BMP_PM, bSleep); // Set powermode + + + if (filtering) + bmp_as_write_register(BMP_SCR, 0x80); // acquire unfiltered acceleration data + + // configure sensor interrupt + bmp_as_write_register(BMP_IMR2, 0x01); // map new data interrupt to INT1 pin + bmp_as_write_register(BMP_ISR2, 0x10); // enable new data interrupt + + // enable CC430 interrupt pin for data read out from acceleration sensor + AS_INT_IFG &= ~AS_INT_PIN; // Reset flag + AS_INT_IE |= AS_INT_PIN; // Enable interrupt +} + +// ************************************************************************************************* +// @fn bmp_as_stop +// @brief Power down acceleration sensor +// @param none +// @return none +// ************************************************************************************************* +void bmp_as_stop(void) +{ + as_stop(); +} + + +// ************************************************************************************************* +// @fn bmp_as_read_register +// @brief Read a byte from the acceleration sensor +// @param uint8_t bAddress Register address +// @return uint8_t Register content +// ************************************************************************************************* +uint8_t bmp_as_read_register(uint8_t bAddress) +{ + bAddress |= BIT7; // set R/W bit for reading + + return as_read_register(bAddress); +} + +// ************************************************************************************************* +// @fn bmp_as_write_register +// @brief Write a byte to the acceleration sensor +// @param uint8_t bAddress Register address +// uint8_t bData Data to write +// @return uint8_t +// ************************************************************************************************* +uint8_t bmp_as_write_register(uint8_t bAddress, uint8_t bData) // NON SCRIVE!!! +{ + // bAddress &= ~BIT8; // R/W bit to be not set + bAddress &= ~BIT7; + + return as_write_register(bAddress, bData); +} + + +// ************************************************************************************************* +// @fn bmp_as_get_data +// @brief Service routine to read acceleration values. +// @param int16_t *axes array containing the acceleration values +// @return none +// ************************************************************************************************* +void bmp_as_get_data(int16_t *axes) +{ + uint8_t i; + uint16_t data[3]; + // Exit if sensor is not powered up + if ((AS_PWR_OUT & AS_PWR_PIN) != AS_PWR_PIN) return; + + // Read LSB from LSB acceleration data first to update MSB (shadowing is enabled by default) + data[0] = ((uint32_t) (bmp_as_read_register(BMP_ACC_X_LSB) & 0xC0)) >> 6; + data[1] = ((uint32_t) (bmp_as_read_register(BMP_ACC_Y_LSB) & 0xC0)) >> 6; + data[2] = ((uint32_t) (bmp_as_read_register(BMP_ACC_Z_LSB) & 0xC0)) >> 6; + // Store X/Y/Z MSB acceleration data in buffer + data[0] += ((uint32_t) bmp_as_read_register(BMP_ACC_X_MSB)) << 2; + data[1] += ((uint32_t) bmp_as_read_register(BMP_ACC_Y_MSB)) << 2; + data[2] += ((uint32_t) bmp_as_read_register(BMP_ACC_Z_MSB)) << 2; + + + // Convert the values from 10 bit two's complement uint to 16 bit int + for (i = 0; i < 3; i++) + if (data[i] & 0x0200) + { + data[i] = (~data[i] & 0x03FF) + 1; + axes[i] = -((int32_t) data[i]); + } + else + axes[i] = data[i]; + +} + +// ************************************************************************************************* +// @fn bmp_as_enable_interrupts +// @brief Enables accelerometer's interrupts on interrupt pin 1 (pin 2 is not connected to the +// ez-Chronos). +// @param bmp_as_interrupts_t Interrupt data structure. +// @return none +// ************************************************************************************************* +void bmp_as_enable_interrupts(bmp_as_interrupts_t interrupts) +{ + uint8_t val = 0; + + // Write the interrupt registers (BMP_ISR1 and BMP_ISR2) + if (interrupts.flat_interrupt) + val |= BIT7; + if (interrupts.orient_interrupt) + val |= BIT6; + if (interrupts.tap_interrupt == 1) + val |= BIT5; + else if (interrupts.tap_interrupt != 0) + val |= BIT4; + if (interrupts.slope_interrupt.z) + val |= BIT2; + if (interrupts.slope_interrupt.y) + val |= BIT1; + if (interrupts.slope_interrupt.x) + val |= BIT0; + + as_write_register(BMP_ISR1, val); + + val = 0; + + if (interrupts.new_interrupt) + val |= BIT4; + if (interrupts.low_interrupt) + val |= BIT3; + if (interrupts.high_interrupt.z) + val |= BIT2; + if (interrupts.high_interrupt.y) + val |= BIT1; + if (interrupts.high_interrupt.x) + val |= BIT0; + + as_write_register(BMP_ISR2, val); + + + // Map every interrupt to pin INT1 (SYS_MSG_AS_INT in messagebus.h). Pin INT2 is NOT connected. + as_write_register(BMP_IMR1, 0xf7); + as_write_register(BMP_IMR2, 0x01); + timer0_delay(100, LPM3_bits); +} + +// ************************************************************************************************* +// @fn bmp_as_disable_interrupts +// @brief Disables accelerometer's interrupts. +// @param none +// @return none +// ************************************************************************************************* +void bmp_as_disable_interrupts(void) +{ + as_write_register(BMP_ISR1, 0x00); + as_write_register(BMP_ISR2, 0x00); + as_write_register(BMP_IMR1, 0x00); + as_write_register(BMP_IMR2, 0x00); + as_write_register(BMP_IMR3, 0x00); + timer0_delay(100, LPM3_bits); +} + + +// ************************************************************************************************* +// @fn bmp_as_process_interrupt +// @brief Processes a generated interrupt. +// @param none +// @return bmp_as_status_t Status data structure. +// ************************************************************************************************* +bmp_as_status_t bmp_as_process_interrupt(void) +{ + bmp_as_status_t ret = bmp_as_init_status(); + uint8_t reg, tmp; + + reg = bmp_as_read_register(0x09); + + // Process tap and slope interrupts. + tmp = bmp_as_read_register(0x0b); + if (reg & BIT2) + { + ret.int_raised.slope_interrupt.x = 1; + ret.slope.sign = (tmp & BIT3)? 1: 0; + ret.slope.first_z = (tmp & BIT2)? 1: 0; + ret.slope.first_y = (tmp & BIT1)? 1: 0; + ret.slope.first_x = (tmp & BIT0)? 1: 0; + } + if (reg & BIT4) + { + ret.int_raised.tap_interrupt = 2; + ret.tap.sign = (tmp & BIT7)? 1: 0; + ret.tap.first_z = (tmp & BIT6)? 1: 0; + ret.tap.first_y = (tmp & BIT5)? 1: 0; + ret.tap.first_x = (tmp & BIT4)? 1: 0; + } + if (reg & BIT5) + { + ret.int_raised.tap_interrupt = 1; + ret.tap.sign = (tmp & BIT7)? 1: 0; + ret.tap.first_z = (tmp & BIT6)? 1: 0; + ret.tap.first_y = (tmp & BIT5)? 1: 0; + ret.tap.first_x = (tmp & BIT4)? 1: 0; + } + + // Process flat, orient and high-g interrupt. + tmp = bmp_as_read_register(0x0c); + if (reg & BIT7) + ret.int_raised.flat_interrupt = (tmp & BIT7)? 1: 0; + if (reg & BIT1) + { + ret.high.sign = (tmp & BIT3)? 1: 0; + ret.high.first_z = (tmp & BIT2)? 1: 0; + ret.high.first_y = (tmp & BIT1)? 1: 0; + ret.high.first_x = (tmp & BIT0)? 1: 0; + ret.int_raised.high_interrupt.x = 1; + } + if (reg & BIT6) + { + ret.int_raised.orient_interrupt = 1; + ret.orient_z = (tmp & BIT6)? 1: 0; + ret.orient_xy = ((tmp & BIT5)? 2 : 0) + ((tmp & BIT4)? 1 : 0); + } + + // Process low-g interrupt. + if (reg & BIT0) + ret.int_raised.low_interrupt = 1; + + // Process new data interrupt. + reg = bmp_as_read_register(0x0a); + if (reg & BIT7) + ret.int_raised.new_interrupt = 1; + + return ret; +} + +// ************************************************************************************************* +// @fn bmp_as_init_interrupts +// @brief Creates an empty interrupt data structure. +// @param none +// @return bmp_as_interrupts_t Empty interrupt data structure. +// ************************************************************************************************* +bmp_as_interrupts_t bmp_as_init_interrupts(void) +{ + bmp_as_interrupts_t ret; + memset(&ret, 0, sizeof(bmp_as_interrupts_t)); + + return ret; +} + +// ************************************************************************************************* +// @fn bmp_as_init_status +// @brief Creates an empty status data structure. +// @param none +// @return bmp_as_status_t Empty status data structure. +// ************************************************************************************************* +bmp_as_status_t bmp_as_init_status(void) +{ + bmp_as_status_t ret; + memset(&ret, 0, sizeof(bmp_as_status_t)); + + return ret; +} diff --git a/drivers/bmp_as.h b/drivers/bmp_as.h new file mode 100644 index 0000000..30f15a8 --- /dev/null +++ b/drivers/bmp_as.h @@ -0,0 +1,182 @@ +// ************************************************************************************************* +// +// Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the +// distribution. +// +// Neither the name of Texas Instruments Incorporated nor the names of +// its contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ************************************************************************************************* + +#ifndef BMP_AS_H_ +#define BMP_AS_H_ + + +// ************************************************************************************************* +// Include section + + +// ************************************************************************************************* + +typedef struct +{ + struct + { + unsigned int x : 1; + unsigned int y : 1; + unsigned int z : 1; + } slope_interrupt; + struct + { + unsigned int x : 1; + unsigned int y : 1; + unsigned int z : 1; + } high_interrupt; + unsigned int flat_interrupt : 1; + unsigned int orient_interrupt : 1; + unsigned int tap_interrupt : 2; // 1 single, 2/3 double, 0 none + unsigned int low_interrupt : 1; + unsigned int new_interrupt : 1; +} bmp_as_interrupts_t; + +typedef struct +{ + bmp_as_interrupts_t int_raised; + struct + { + unsigned int sign : 1; // 1 -, 0 + + unsigned int first_x : 1; + unsigned int first_y : 1; + unsigned int first_z : 1; + } high; + struct + { + unsigned int sign : 1; + unsigned int first_x : 1; + unsigned int first_y : 1; + unsigned int first_z : 1; + } tap; + + struct + { + unsigned int sign : 1; + unsigned int first_x : 1; + unsigned int first_y : 1; + unsigned int first_z : 1; + } slope; + unsigned int orient_z : 1; // 0 upward, 1 downward + unsigned int orient_xy : 2; // 00 portrait upright, 01 portrait upside-down, 10, landscape left, 11 landscape right + +} bmp_as_status_t; + +// Prototypes section +extern void as_init(void); +extern void as_start(void); +extern void as_stop(void); +extern uint8_t as_read_register(uint8_t bAddress); +extern uint8_t as_write_register(uint8_t bAddress, uint8_t bData); +extern void bmp_as_start(uint8_t bGRange, uint8_t bBwd, uint8_t bSleep, uint8_t filtering); +extern void bmp_as_stop(void); +extern uint8_t bmp_as_read_register(uint8_t bAddress); +extern uint8_t bmp_as_write_register(uint8_t bAddress, uint8_t bData); +extern void bmp_as_get_data(int16_t * axes); +extern void bmp_as_enable_interrupts(bmp_as_interrupts_t interrupts); +extern void bmp_as_disable_interrupts(void); +extern bmp_as_status_t bmp_as_process_interrupt(void); +extern bmp_as_status_t bmp_as_init_status(void); +extern bmp_as_interrupts_t bmp_as_init_interrupts(void); + +// ************************************************************************************************* +// Defines section + +#define BMP_RSTKEY (0xB6) + +/******************************************************************** + * + * Bosch BMA250 + * Register Map + * + ********************************************************************/ + +#define BMP_CHIPID (0x00) +#define BMP_ACC_X_LSB (0x02) +#define BMP_ACC_X_MSB (0x03) +#define BMP_ACC_Y_LSB (0x04) +#define BMP_ACC_Y_MSB (0x05) +#define BMP_ACC_Z_LSB (0x06) +#define BMP_ACC_Z_MSB (0x07) + +#define BMP_GRANGE (0x0F) // g Range +#define BMP_BWD (0x10) // Bandwidth +#define BMP_PM (0x11) // Power modes +#define BMP_SCR (0x13) // Special Control Register +#define BMP_RESET (0x14) // Soft reset register (writing 0xB6 causes reset) +#define BMP_ISR1 (0x16) // Interrupt settings register 1 +#define BMP_ISR2 (0x17) // Interrupt settings register 2 +#define BMP_IMR1 (0x19) // Interrupt mapping register 1 +#define BMP_IMR2 (0x1A) // Interrupt mapping register 2 +#define BMP_IMR3 (0x1B) // Interrupt mapping register 3 + +/* Configuration constants */ + +#define BMP_GRANGE_2G (0x03) // +- 2g +#define BMP_GRANGE_4G (0x05) // -+ 4g +#define BMP_GRANGE_8G (0x08) // -+ 8g +#define BMP_GRANGE_16G (0x0C) // -+ 16g + +#define BMP_SLEEP_NO (0x00) +#define BMP_SLEEP_05MS (0x4A) // Approx. 100uA current consumption +#define BMP_SLEEP_1MS (0x4C) +#define BMP_SLEEP_2MS (0x4E) // Approx. 55uA +#define BMP_SLEEP_4MS (0x50) +#define BMP_SLEEP_6MS (0x52) +#define BMP_SLEEP_10MS (0x54) // Approx. 16uA +#define BMP_SLEEP_25MS (0x56) +#define BMP_SLEEP_50MS (0x58) +#define BMP_SLEEP_100MS (0x5A) +#define BMP_SLEEP_500MS (0x5C) +#define BMP_SLEEP_1000MS (0x5E) // Approx. 0.7uA + +#define BMP_BWD_7HZ (0x08) // 7.81 Hz +#define BMP_BWD_15HZ (0x09) // 15.63 Hz +#define BMP_BWD_31HZ (0x0A) // 31.25 Hz +#define BMP_BWD_62HZ (0x0B) // 62.5 Hz +#define BMP_BWD_125HZ (0x0C) // 125 Hz +#define BMP_BWD_250HZ (0x0D) // 250 Hz +#define BMP_BWD_500HZ (0x0E) // 500 Hz +#define BMP_BWD_1000HZ (0x0F) // 1000 Hz + +// ************************************************************************************************* +// Global Variable section + + +// ************************************************************************************************* +// Extern section + + +#endif /*BMP_AS_H_*/ diff --git a/drivers/bmp_ps.c b/drivers/bmp_ps.c new file mode 100644 index 0000000..f48f2e8 --- /dev/null +++ b/drivers/bmp_ps.c @@ -0,0 +1,247 @@ +// ************************************************************************************************* +// +// Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the +// distribution. +// +// Neither the name of Texas Instruments Incorporated nor the names of +// its contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ************************************************************************************************* +// Bosch BMP085 pressure sensor driver functions +// ************************************************************************************************* + +// ************************************************************************************************* +// Include section + +// system +#include "openchronos.h" + +// driver +#include "bmp_ps.h" +#include "ps.h" +#include "timer.h" + +// ************************************************************************************************* +// Prototypes section + +// ************************************************************************************************* +// Defines section + +// ************************************************************************************************* +// Global Variable section + +// Variable to hold BMP085 calibration data +bmp_085_calibration_param_t bmp_cal_param; +// Paramater used by temperature and pressure measurement +long bmp_param_b5; + +// ************************************************************************************************* +// Extern section + +// ************************************************************************************************* +// @fn bmp_ps_init +// @brief Init pressure sensor I/O +// @param none +// @return none +// ************************************************************************************************* +void bmp_ps_init(void) +{ + ps_init(); + + // Read ChipID to check if communication is working + bmp_ps_read_register(BMP_085_CHIP_ID_REG, PS_I2C_8BIT_ACCESS); + bmp_ps_get_cal_param(); +} + + +// ************************************************************************************************* +// @fn bmp_ps_get_cal_param +// @brief read out calibration parameters from BMP085 memory to cal_param +// @param none +// @return none +// ************************************************************************************************* +void bmp_ps_get_cal_param(void) +{ + /*parameters AC1-AC6*/ + bmp_cal_param.ac1 = bmp_ps_read_register(BMP_085_PROM_START_ADDR + 0, PS_I2C_16BIT_ACCESS); + bmp_cal_param.ac2 = bmp_ps_read_register(BMP_085_PROM_START_ADDR + 2, PS_I2C_16BIT_ACCESS); + bmp_cal_param.ac3 = bmp_ps_read_register(BMP_085_PROM_START_ADDR + 4, PS_I2C_16BIT_ACCESS); + bmp_cal_param.ac4 = bmp_ps_read_register(BMP_085_PROM_START_ADDR + 6, PS_I2C_16BIT_ACCESS); + bmp_cal_param.ac5 = bmp_ps_read_register(BMP_085_PROM_START_ADDR + 8, PS_I2C_16BIT_ACCESS); + bmp_cal_param.ac6 = bmp_ps_read_register(BMP_085_PROM_START_ADDR + 10,PS_I2C_16BIT_ACCESS); + + /*parameters B1,B2*/ + bmp_cal_param.b1 = bmp_ps_read_register(BMP_085_PROM_START_ADDR + 12, PS_I2C_16BIT_ACCESS); + bmp_cal_param.b2 = bmp_ps_read_register(BMP_085_PROM_START_ADDR + 14, PS_I2C_16BIT_ACCESS); + + /*parameters MB,MC,MD*/ + bmp_cal_param.mb = bmp_ps_read_register(BMP_085_PROM_START_ADDR + 16, PS_I2C_16BIT_ACCESS); + bmp_cal_param.mc = bmp_ps_read_register(BMP_085_PROM_START_ADDR + 18, PS_I2C_16BIT_ACCESS); + bmp_cal_param.md = bmp_ps_read_register(BMP_085_PROM_START_ADDR + 20, PS_I2C_16BIT_ACCESS); +} + +// ************************************************************************************************* +// @fn bmp_ps_start +// @brief Init pressure sensor registers and start sampling +// @param none +// @return none +// ************************************************************************************************* +void bmp_ps_start(void) +{ + PS_INT_IFG &= ~PS_INT_PIN; + PS_INT_IE |= PS_INT_PIN; + // Start sampling pressure and temperature + bmp_ps_get_pa(); + bmp_ps_get_temp(); +} + +// ************************************************************************************************* +// @fn bmp_ps_stop +// @brief Power down pressure sensor +// @param none +// @return none +// ************************************************************************************************* +void bmp_ps_stop(void) +{ + // Simply disable interrupts, sensor is in powerdown after measurement + PS_INT_IE &= ~PS_INT_PIN; + PS_INT_IFG &= ~PS_INT_PIN; +} + +// ************************************************************************************************* +// @fn bmp_ps_write_register +// @brief Write a byte to the pressure sensor +// @param uint8_t address Register address +// uint8_t data Data to write +// @return uint8_t +// ************************************************************************************************* +uint8_t bmp_ps_write_register(uint8_t address, uint8_t data) +{ + return ps_write_register(BMP_085_I2C_ADDR << 1, address, data); +} + +// ************************************************************************************************* +// @fn bmp_ps_read_register +// @brief Read a byte from the pressure sensor +// @param uint8_t address Register address +// uint8_t mode PS_I2C_8BIT_ACCESS, PS_I2C_16BIT_ACCESS +// @return uint16_t Register content +// ************************************************************************************************* +uint16_t bmp_ps_read_register(uint8_t address, uint8_t mode) +{ + return ps_read_register(BMP_085_I2C_ADDR << 1, address, mode); +} + +// ************************************************************************************************* +// @fn bmp_ps_get_pa +// @brief Read out pressure. Format is Pa. Range is 30000 .. 120000 Pa. +// @param none +// @return uint32_t 15-bit pressure sensor value (Pa) +// ************************************************************************************************* +uint32_t bmp_ps_get_pa(void) +{ + uint16_t up; // uncompensated pressure + int32_t pressure, x1, x2, x3, b3, b6; + uint32_t result, b4, b7; + + // Add Compensation and convert decimal value to Pa + + bmp_ps_write_register(BMP_085_CTRL_MEAS_REG, BMP_085_P_MEASURE); + while ((PS_INT_IN & PS_INT_PIN) == 0); + + b6 = bmp_param_b5 - 4000; + //*****calculate B3************ + x1 = (b6 * b6) >> 12; + x1 = (bmp_cal_param.b2 * x1) / 2048; + + x2 = (bmp_cal_param.ac2 * b6) / 2048; + + x3 = x1 + x2; + + b3 = (((((long) bmp_cal_param.ac1) * 4 + x3)) + 2) / 4; + + //*****calculate B4************ + x1 = (bmp_cal_param.ac3 * b6) / 8192; + x2 = (bmp_cal_param.b1 * ((b6 * b6) >> 12)) / 65536; + x3 = ((x1 + x2) + 2) / 4; + b4 = (bmp_cal_param.ac4 * (uint32_t) (x3 + 32768)) / 32768; + + // Get MSB from ADC_OUT_MSB_REG + up = bmp_ps_read_register(BMP_085_ADC_OUT_MSB_REG, PS_I2C_16BIT_ACCESS); + + b7 = ((uint32_t)(up - b3) * 50000); + if (b7 < 0x80000000) + { + pressure = (b7 * 2) / b4; + } + else + { + pressure = (b7 / b4) * 2; + } + + x1 = pressure / 256; + x1 *= x1; + x1 = (x1 * BMP_SMD500_PARAM_MG) / 65536; + x2 = (pressure * BMP_SMD500_PARAM_MH) / 65536; + result = pressure + (x1 + x2 + BMP_SMD500_PARAM_MI) / 16; // pressure in Pa + + return (result); +} + +// ************************************************************************************************* +// @fn bmp_ps_get_temp +// @brief Read out temperature. +// @param none +// @return uint16_t 13-bit temperature value in xx.x K format +// ************************************************************************************************* +uint16_t bmp_ps_get_temp(void) +{ + uint16_t ut; + int32_t x1, x2; + int16_t temperature; + uint16_t kelvin; + + bmp_ps_write_register(BMP_085_CTRL_MEAS_REG, BMP_085_T_MEASURE); + while ((PS_INT_IN & PS_INT_PIN) == 0); + + // Get temp bits from ADC_OUT registers + ut = bmp_ps_read_register(BMP_085_ADC_OUT_MSB_REG, PS_I2C_16BIT_ACCESS); + + // Add Compensation and convert decimal value to 0.1 C + x1 = (((long) ut - (long) bmp_cal_param.ac6) * (long) bmp_cal_param.ac5) / 32768; + x2 = ((long) bmp_cal_param.mc * 2048) / (x1 + bmp_cal_param.md); + bmp_param_b5 = x1 + x2; + + temperature = ((bmp_param_b5 + 8) / 16); // temperature in 0.1C + + // Convert from C to K + kelvin = 2732 + temperature; + + return (kelvin); +} + diff --git a/drivers/bmp_ps.h b/drivers/bmp_ps.h new file mode 100644 index 0000000..b611674 --- /dev/null +++ b/drivers/bmp_ps.h @@ -0,0 +1,104 @@ +// ************************************************************************************************* +// +// Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the +// distribution. +// +// Neither the name of Texas Instruments Incorporated nor the names of +// its contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ************************************************************************************************* + +#ifndef BMP_PS_H_ +#define BMP_PS_H_ + +// ************************************************************************************************* +// Include section + +// ************************************************************************************************* +// Prototypes section +extern void bmp_ps_init(void); +extern void bmp_ps_get_cal_param(void); +extern void bmp_ps_start(void); +extern void bmp_ps_stop(void); +extern uint16_t bmp_ps_read_register(uint8_t address, uint8_t mode); +extern uint8_t bmp_ps_write_register(uint8_t address, uint8_t data); +extern uint32_t bmp_ps_get_pa(void); +extern uint16_t bmp_ps_get_temp(void); + +// ************************************************************************************************* +// Defines section + +// Bosch BMP085 defines + +#define BMP_085_CHIP_ID (0x55) +#define BMP_085_I2C_ADDR (0xEE >> 1) + +#define BMP_085_PROM_START_ADDR (0xAA) +#define BMP_085_CHIP_ID_REG (0xD0) +#define BMP_085_VERSION_REG (0xD1) + +#define BMP_085_CTRL_MEAS_REG (0xF4) +#define BMP_085_ADC_OUT_MSB_REG (0xF6) +#define BMP_085_ADC_OUT_LSB_REG (0xF7) + +#define BMP_085_SOFT_RESET_REG (0xE0) + +#define BMP_085_T_MEASURE (0x2E) // temperature measurent +#define BMP_085_P_MEASURE (0x34) // pressure measurement + +#define BMP_085_TEMP_CONVERSION_TIME (5) // TO be spec'd by GL or SB + +#define BMP_SMD500_PARAM_MG (3038) //calibration parameter +#define BMP_SMD500_PARAM_MH (-7357) //calibration parameter +#define BMP_SMD500_PARAM_MI (3791) //calibration parameter +#define BMP_SMD500_PARAM_MJ (64385) //calibration parameter + +/** this structure holds all device specific calibration parameters + */ +typedef struct { + short ac1; + short ac2; + short ac3; + unsigned short ac4; + unsigned short ac5; + unsigned short ac6; + short b1; + short b2; + short mb; + short mc; + short md; +} bmp_085_calibration_param_t; + +// ************************************************************************************************* +// Global Variable section + + +// ************************************************************************************************* +// Extern section + +#endif /*BMP_PS_H_ */ diff --git a/drivers/buzzer.c b/drivers/buzzer.c index dff79ab..f768869 100644 --- a/drivers/buzzer.c +++ b/drivers/buzzer.c @@ -33,86 +33,86 @@ note welcome[4] = {0x1931, 0x1934, 0x1938, 0x000F}; // The following note table is calculated using "clock frequency in hz / sound frequency in hz" uint16_t base_notes[13] = { - 0, /* 0: P */ - 27273, /* 1: A */ - 25742, /* 2: A# */ - 24397, /* 3: B */ - 22934, /* 4: C */ - 21646, /* 5: C# */ - 20431, /* 6: D */ - 19285, /* 7: D# */ - 18202, /* 8: E */ - 17181, /* 9: F */ - 16216, /* A: F# */ - 15306, /* B: G */ - 14447 /* C: G# */ + 0, /* 0: P */ + 27273, /* 1: A */ + 25742, /* 2: A# */ + 24397, /* 3: B */ + 22934, /* 4: C */ + 21646, /* 5: C# */ + 20431, /* 6: D */ + 19285, /* 7: D# */ + 18202, /* 8: E */ + 17181, /* 9: F */ + 16216, /* A: F# */ + 15306, /* B: G */ + 14447 /* C: G# */ }; volatile static note *notes = NULL; inline bool is_buzzer_playing() { - return notes != NULL; + return notes != NULL; } inline void buzzer_init(void) { - /* Reset TA1R, TA1 runs from 32768Hz ACLK */ - TA1CTL = TACLR | TASSEL__SMCLK | MC__STOP; + /* Reset TA1R, TA1 runs from 32768Hz ACLK */ + TA1CTL = TACLR | TASSEL__SMCLK | MC__STOP; - /* Enable IRQ, set output mode "toggle" */ - TA1CCTL0 = OUTMOD_4; + /* Enable IRQ, set output mode "toggle" */ + TA1CCTL0 = OUTMOD_4; - /* Play "welcome" chord: A major */ - buzzer_play(welcome); + /* Play "welcome" chord: A major */ + buzzer_play(welcome); } inline static void buzzer_stop(void) { - /* Stop PWM timer */ - TA1CTL &= ~MC_3; // Clear any MC bits, effectively a MC_STOP + /* Stop PWM timer */ + TA1CTL &= ~MC_3; // Clear any MC bits, effectively a MC_STOP - /* Disable buzzer PWM output */ - P2OUT &= ~BIT7; - P2SEL &= ~BIT7; + /* Disable buzzer PWM output */ + P2OUT &= ~BIT7; + P2SEL &= ~BIT7; - /* Clear PWM timer interrupt */ - TA1CCTL0 &= ~CCIE; + /* Clear PWM timer interrupt */ + TA1CCTL0 &= ~CCIE; } static void buzzer_play_callback() { - /* 0x000F is the "stop bit" */ - if (PITCH(*notes) != 0x000F) { - if (PITCH(*notes) == 0) { - /* Stop the timer! We are playing a rest */ - TA1CTL &= ~MC_3; - } else { - /* Set PWM frequency */ - TA1CCR0 = base_notes[PITCH(*notes)] >> OCTAVE(*notes); - - /* Start the timer */ - TA1CTL |= MC__UP; - } - - /* Calculate duration delay in ms */ - uint16_t delay = DURATION(*notes); - - /* Advance to the next note */ - notes++; - - /* Delay for DURATION(*notes) milliseconds */ - timer0_delay_callback(delay, &buzzer_play_callback); - } else { - /* Stop buzzer */ - buzzer_stop(); - notes = NULL; - } + /* 0x000F is the "stop bit" */ + if (PITCH(*notes) != 0x000F) { + if (PITCH(*notes) == 0) { + /* Stop the timer! We are playing a rest */ + TA1CTL &= ~MC_3; + } else { + /* Set PWM frequency */ + TA1CCR0 = base_notes[PITCH(*notes)] >> OCTAVE(*notes); + + /* Start the timer */ + TA1CTL |= MC__UP; + } + + /* Calculate duration delay in ms */ + uint16_t delay = DURATION(*notes); + + /* Advance to the next note */ + notes++; + + /* Delay for DURATION(*notes) milliseconds */ + timer0_delay_callback(delay, &buzzer_play_callback); + } else { + /* Stop buzzer */ + buzzer_stop(); + notes = NULL; + } } void buzzer_play(note *async_notes) { - if (notes) return; // Ignore if we are currently playing. + if (notes) return; // Ignore if we are currently playing. - notes = async_notes; + notes = async_notes; - /* Allow buzzer PWM output on P2.7 */ - P2SEL |= BIT7; + /* Allow buzzer PWM output on P2.7 */ + P2SEL |= BIT7; - buzzer_play_callback(); -} \ No newline at end of file + buzzer_play_callback(); +} diff --git a/drivers/buzzer.h b/drivers/buzzer.h index aaa6a84..0a6d0e1 100644 --- a/drivers/buzzer.h +++ b/drivers/buzzer.h @@ -1,24 +1,24 @@ /** - drivers/timer.h: Openchronos TA0 timer driver + drivers/timer.h: Openchronos TA0 timer driver - Copyright (C) 2012 Aljaž Srebrnič + Copyright (C) 2012 Aljaž Srebrnič - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ /*! diff --git a/drivers/display.c b/drivers/display.c index e831c29..941039d 100644 --- a/drivers/display.c +++ b/drivers/display.c @@ -1,24 +1,24 @@ /** - drivers/display.c: Display driver for the eZ430-chronos + drivers/display.c: Display driver for the eZ430-chronos - Copyright (C) 2012 Angelo Arrifano + Copyright (C) 2012 Angelo Arrifano - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ // ************************************************************************************************* @@ -198,155 +198,155 @@ static uint8_t display_activescr; #define SEG_G (BIT1) /* Table with memory bit assignment for digits "0"-"9" and chars "A"-"Z" - A + A F B - G + G E C - D + D */ static const uint8_t lcd_font[] = { - SEG_A + SEG_B + SEG_C + SEG_D + SEG_E + SEG_F , // Displays "0" - SEG_B + SEG_C , // Displays "1" - SEG_A + SEG_B + SEG_D + SEG_E + SEG_G, // Displays "2" - SEG_A + SEG_B + SEG_C + SEG_D + SEG_G, // Displays "3" - SEG_B + SEG_C + SEG_F + SEG_G, // Displays "4" - SEG_A + SEG_C + SEG_D + SEG_F + SEG_G, // Displays "5" - SEG_A + SEG_C + SEG_D + SEG_E + SEG_F + SEG_G, // Displays "6" - SEG_A + SEG_B + SEG_C , // Displays "7" - SEG_A + SEG_B + SEG_C + SEG_D + SEG_E + SEG_F + SEG_G, // Displays "8" - SEG_A + SEG_B + SEG_C + SEG_D + SEG_F + SEG_G, // Displays "9" - 0 , // Displays " " (:) - 0 , // Displays " " (;) - SEG_A + SEG_F + SEG_G, // Displays "<" as high c - SEG_D + SEG_G, // Displays "=" - 0 , // Displays " " (>) - SEG_A + SEG_B + SEG_E + SEG_G, // Displays "?" - 0 , // Displays " " (@) - SEG_A + SEG_B + SEG_C + SEG_E + SEG_F + SEG_G, // Displays "A" - SEG_C + SEG_D + SEG_E + SEG_F + SEG_G, // Displays "b" - SEG_D + SEG_E + SEG_G, // Displays "c" - SEG_B + SEG_C + SEG_D + SEG_E + SEG_G, // Displays "d" - SEG_A + + SEG_D + SEG_E + SEG_F + SEG_G, // Displays "E" - SEG_A + SEG_E + SEG_F + SEG_G, // Displays "f" - SEG_A + SEG_B + SEG_C + SEG_D + SEG_F + SEG_G, // Displays "g" same as 9 - SEG_C + SEG_E + SEG_F + SEG_G, // Displays "h" - SEG_E , // Displays "i" - SEG_A + SEG_B + SEG_C + SEG_D , // Displays "J" - SEG_D + SEG_F + SEG_G, // Displays "k" - SEG_D + SEG_E + SEG_F , // Displays "L" - SEG_A + SEG_B + SEG_C + SEG_E + SEG_F , // Displays "M" - SEG_C + SEG_E + SEG_G, // Displays "n" - SEG_C + SEG_D + SEG_E + SEG_G, // Displays "o" - SEG_A + SEG_B + SEG_E + SEG_F + SEG_G, // Displays "P" - SEG_A + SEG_B + SEG_C + SEG_F + SEG_G, // Displays "q" - SEG_E + SEG_G, // Displays "r" - SEG_A + SEG_C + SEG_D + SEG_F + SEG_G, // Displays "S" same as 5 - SEG_D + SEG_E + SEG_F + SEG_G, // Displays "t" - SEG_C + SEG_D + SEG_E , // Displays "u" - SEG_C + SEG_D + SEG_E , // Displays "v" same as u - SEG_B + SEG_C + SEG_D + SEG_E + SEG_F + SEG_G, // Displays "W" - SEG_B + SEG_C + + SEG_E + SEG_F + SEG_G, // Displays "X" as H - SEG_B + SEG_C + SEG_D + SEG_F + SEG_G, // Displays "Y" - SEG_A + SEG_B + SEG_D + SEG_E + SEG_G, // Displays "Z" same as 2 - SEG_B + SEG_E + SEG_G, // Displays "[" as _|` - SEG_A + SEG_B + SEG_F + SEG_G, // Displays "\" (#) - SEG_C + SEG_F + SEG_G, // Displays "]" as `|_ - SEG_A , // Displays "^" - SEG_D // Displays "_" + SEG_A + SEG_B + SEG_C + SEG_D + SEG_E + SEG_F , // Displays "0" + SEG_B + SEG_C , // Displays "1" + SEG_A + SEG_B + SEG_D + SEG_E + SEG_G, // Displays "2" + SEG_A + SEG_B + SEG_C + SEG_D + SEG_G, // Displays "3" + SEG_B + SEG_C + SEG_F + SEG_G, // Displays "4" + SEG_A + SEG_C + SEG_D + SEG_F + SEG_G, // Displays "5" + SEG_A + SEG_C + SEG_D + SEG_E + SEG_F + SEG_G, // Displays "6" + SEG_A + SEG_B + SEG_C , // Displays "7" + SEG_A + SEG_B + SEG_C + SEG_D + SEG_E + SEG_F + SEG_G, // Displays "8" + SEG_A + SEG_B + SEG_C + SEG_D + SEG_F + SEG_G, // Displays "9" + 0 , // Displays " " (:) + 0 , // Displays " " (;) + SEG_A + SEG_F + SEG_G, // Displays "<" as high c + SEG_D + SEG_G, // Displays "=" + 0 , // Displays " " (>) + SEG_A + SEG_B + SEG_E + SEG_G, // Displays "?" + 0 , // Displays " " (@) + SEG_A + SEG_B + SEG_C + SEG_E + SEG_F + SEG_G, // Displays "A" + SEG_C + SEG_D + SEG_E + SEG_F + SEG_G, // Displays "b" + SEG_D + SEG_E + SEG_G, // Displays "c" + SEG_B + SEG_C + SEG_D + SEG_E + SEG_G, // Displays "d" + SEG_A + + SEG_D + SEG_E + SEG_F + SEG_G, // Displays "E" + SEG_A + SEG_E + SEG_F + SEG_G, // Displays "f" + SEG_A + SEG_B + SEG_C + SEG_D + SEG_F + SEG_G, // Displays "g" same as 9 + SEG_C + SEG_E + SEG_F + SEG_G, // Displays "h" + SEG_E , // Displays "i" + SEG_A + SEG_B + SEG_C + SEG_D , // Displays "J" + SEG_D + SEG_F + SEG_G, // Displays "k" + SEG_D + SEG_E + SEG_F , // Displays "L" + SEG_A + SEG_B + SEG_C + SEG_E + SEG_F , // Displays "M" + SEG_C + SEG_E + SEG_G, // Displays "n" + SEG_C + SEG_D + SEG_E + SEG_G, // Displays "o" + SEG_A + SEG_B + SEG_E + SEG_F + SEG_G, // Displays "P" + SEG_A + SEG_B + SEG_C + SEG_F + SEG_G, // Displays "q" + SEG_E + SEG_G, // Displays "r" + SEG_A + SEG_C + SEG_D + SEG_F + SEG_G, // Displays "S" same as 5 + SEG_D + SEG_E + SEG_F + SEG_G, // Displays "t" + SEG_C + SEG_D + SEG_E , // Displays "u" + SEG_C + SEG_D + SEG_E , // Displays "v" same as u + SEG_B + SEG_C + SEG_D + SEG_E + SEG_F + SEG_G, // Displays "W" + SEG_B + SEG_C + + SEG_E + SEG_F + SEG_G, // Displays "X" as H + SEG_B + SEG_C + SEG_D + SEG_F + SEG_G, // Displays "Y" + SEG_A + SEG_B + SEG_D + SEG_E + SEG_G, // Displays "Z" same as 2 + SEG_B + SEG_E + SEG_G, // Displays "[" as _|` + SEG_A + SEG_B + SEG_F + SEG_G, // Displays "\" (#) + SEG_C + SEG_F + SEG_G, // Displays "]" as `|_ + SEG_A , // Displays "^" + SEG_D // Displays "_" }; /* Table with memory address for each display element */ static const uint8_t *segments_lcdmem[] = { - LCD_SYMB_AM_MEM, - LCD_SYMB_PM_MEM, - LCD_SYMB_ARROW_UP_MEM, - LCD_SYMB_ARROW_DOWN_MEM, - LCD_SYMB_PERCENT_MEM, - LCD_SYMB_TOTAL_MEM, - LCD_SYMB_AVERAGE_MEM, - LCD_SYMB_MAX_MEM, - LCD_SYMB_BATTERY_MEM, - LCD_UNIT_L1_FT_MEM, - LCD_UNIT_L1_K_MEM, - LCD_UNIT_L1_M_MEM, - LCD_UNIT_L1_I_MEM, - LCD_UNIT_L1_PER_S_MEM, - LCD_UNIT_L1_PER_H_MEM, - LCD_UNIT_L1_DEGREE_MEM, - LCD_UNIT_L2_KCAL_MEM, - LCD_UNIT_L2_KM_MEM, - LCD_UNIT_L2_MI_MEM, - LCD_ICON_HEART_MEM, - LCD_ICON_STOPWATCH_MEM, - LCD_ICON_RECORD_MEM, - LCD_ICON_ALARM_MEM, - LCD_ICON_BEEPER1_MEM, - LCD_ICON_BEEPER2_MEM, - LCD_ICON_BEEPER3_MEM, - LCD_SEG_L1_3_MEM, - LCD_SEG_L1_2_MEM, - LCD_SEG_L1_1_MEM, - LCD_SEG_L1_0_MEM, - LCD_SEG_L1_COL_MEM, - LCD_SEG_L1_DP1_MEM, - LCD_SEG_L1_DP0_MEM, - LCD_SEG_L2_5_MEM, - LCD_SEG_L2_4_MEM, - LCD_SEG_L2_3_MEM, - LCD_SEG_L2_2_MEM, - LCD_SEG_L2_1_MEM, - LCD_SEG_L2_0_MEM, - LCD_SEG_L2_COL1_MEM, - LCD_SEG_L2_COL0_MEM, - LCD_SEG_L2_DP_MEM, + LCD_SYMB_AM_MEM, + LCD_SYMB_PM_MEM, + LCD_SYMB_ARROW_UP_MEM, + LCD_SYMB_ARROW_DOWN_MEM, + LCD_SYMB_PERCENT_MEM, + LCD_SYMB_TOTAL_MEM, + LCD_SYMB_AVERAGE_MEM, + LCD_SYMB_MAX_MEM, + LCD_SYMB_BATTERY_MEM, + LCD_UNIT_L1_FT_MEM, + LCD_UNIT_L1_K_MEM, + LCD_UNIT_L1_M_MEM, + LCD_UNIT_L1_I_MEM, + LCD_UNIT_L1_PER_S_MEM, + LCD_UNIT_L1_PER_H_MEM, + LCD_UNIT_L1_DEGREE_MEM, + LCD_UNIT_L2_KCAL_MEM, + LCD_UNIT_L2_KM_MEM, + LCD_UNIT_L2_MI_MEM, + LCD_ICON_HEART_MEM, + LCD_ICON_STOPWATCH_MEM, + LCD_ICON_RECORD_MEM, + LCD_ICON_ALARM_MEM, + LCD_ICON_BEEPER1_MEM, + LCD_ICON_BEEPER2_MEM, + LCD_ICON_BEEPER3_MEM, + LCD_SEG_L1_3_MEM, + LCD_SEG_L1_2_MEM, + LCD_SEG_L1_1_MEM, + LCD_SEG_L1_0_MEM, + LCD_SEG_L1_COL_MEM, + LCD_SEG_L1_DP1_MEM, + LCD_SEG_L1_DP0_MEM, + LCD_SEG_L2_5_MEM, + LCD_SEG_L2_4_MEM, + LCD_SEG_L2_3_MEM, + LCD_SEG_L2_2_MEM, + LCD_SEG_L2_1_MEM, + LCD_SEG_L2_0_MEM, + LCD_SEG_L2_COL1_MEM, + LCD_SEG_L2_COL0_MEM, + LCD_SEG_L2_DP_MEM, }; /* Table with bit mask for each display element */ static const uint8_t segments_bitmask[] = { - LCD_SYMB_AM_MASK, - LCD_SYMB_PM_MASK, - LCD_SYMB_ARROW_UP_MASK, - LCD_SYMB_ARROW_DOWN_MASK, - LCD_SYMB_PERCENT_MASK, - LCD_SYMB_TOTAL_MASK, - LCD_SYMB_AVERAGE_MASK, - LCD_SYMB_MAX_MASK, - LCD_SYMB_BATTERY_MASK, - LCD_UNIT_L1_FT_MASK, - LCD_UNIT_L1_K_MASK, - LCD_UNIT_L1_M_MASK, - LCD_UNIT_L1_I_MASK, - LCD_UNIT_L1_PER_S_MASK, - LCD_UNIT_L1_PER_H_MASK, - LCD_UNIT_L1_DEGREE_MASK, - LCD_UNIT_L2_KCAL_MASK, - LCD_UNIT_L2_KM_MASK, - LCD_UNIT_L2_MI_MASK, - LCD_ICON_HEART_MASK, - LCD_ICON_STOPWATCH_MASK, - LCD_ICON_RECORD_MASK, - LCD_ICON_ALARM_MASK, - LCD_ICON_BEEPER1_MASK, - LCD_ICON_BEEPER2_MASK, - LCD_ICON_BEEPER3_MASK, - LCD_SEG_L1_3_MASK, - LCD_SEG_L1_2_MASK, - LCD_SEG_L1_1_MASK, - LCD_SEG_L1_0_MASK, - LCD_SEG_L1_COL_MASK, - LCD_SEG_L1_DP1_MASK, - LCD_SEG_L1_DP0_MASK, - LCD_SEG_L2_5_MASK, - LCD_SEG_L2_4_MASK, - LCD_SEG_L2_3_MASK, - LCD_SEG_L2_2_MASK, - LCD_SEG_L2_1_MASK, - LCD_SEG_L2_0_MASK, - LCD_SEG_L2_COL1_MASK, - LCD_SEG_L2_COL0_MASK, - LCD_SEG_L2_DP_MASK, + LCD_SYMB_AM_MASK, + LCD_SYMB_PM_MASK, + LCD_SYMB_ARROW_UP_MASK, + LCD_SYMB_ARROW_DOWN_MASK, + LCD_SYMB_PERCENT_MASK, + LCD_SYMB_TOTAL_MASK, + LCD_SYMB_AVERAGE_MASK, + LCD_SYMB_MAX_MASK, + LCD_SYMB_BATTERY_MASK, + LCD_UNIT_L1_FT_MASK, + LCD_UNIT_L1_K_MASK, + LCD_UNIT_L1_M_MASK, + LCD_UNIT_L1_I_MASK, + LCD_UNIT_L1_PER_S_MASK, + LCD_UNIT_L1_PER_H_MASK, + LCD_UNIT_L1_DEGREE_MASK, + LCD_UNIT_L2_KCAL_MASK, + LCD_UNIT_L2_KM_MASK, + LCD_UNIT_L2_MI_MASK, + LCD_ICON_HEART_MASK, + LCD_ICON_STOPWATCH_MASK, + LCD_ICON_RECORD_MASK, + LCD_ICON_ALARM_MASK, + LCD_ICON_BEEPER1_MASK, + LCD_ICON_BEEPER2_MASK, + LCD_ICON_BEEPER3_MASK, + LCD_SEG_L1_3_MASK, + LCD_SEG_L1_2_MASK, + LCD_SEG_L1_1_MASK, + LCD_SEG_L1_0_MASK, + LCD_SEG_L1_COL_MASK, + LCD_SEG_L1_DP1_MASK, + LCD_SEG_L1_DP0_MASK, + LCD_SEG_L2_5_MASK, + LCD_SEG_L2_4_MASK, + LCD_SEG_L2_3_MASK, + LCD_SEG_L2_2_MASK, + LCD_SEG_L2_1_MASK, + LCD_SEG_L2_0_MASK, + LCD_SEG_L2_COL1_MASK, + LCD_SEG_L2_COL0_MASK, + LCD_SEG_L2_DP_MASK, }; /*************************************************************************** @@ -354,27 +354,27 @@ static const uint8_t segments_bitmask[] = { **************************************************************************/ static void write_lcd_mem(uint8_t *segmem, uint8_t *blkmem, - uint8_t bits, uint8_t bitmask, uint8_t state) + uint8_t bits, uint8_t bitmask, uint8_t state) { - if ( (state | SEG_OFF) == state) { - // Clear all segments - *segmem = (uint8_t)(*segmem & ~bitmask); - } - - if ( (state | SEG_ON) == state) { - // Set visible segments - *segmem = (uint8_t)(*segmem | bits); - } - - if ( (state | BLINK_OFF) == state) { - // Clear blink segments - *blkmem = (uint8_t)(*blkmem & ~bitmask); - } - - if ( (state | BLINK_ON) == state) { - // Set blink segments - *blkmem = (uint8_t)(*blkmem | bits); - } + if ( (state | SEG_OFF) == state) { + // Clear all segments + *segmem = (uint8_t)(*segmem & ~bitmask); + } + + if ( (state | SEG_ON) == state) { + // Set visible segments + *segmem = (uint8_t)(*segmem | bits); + } + + if ( (state | BLINK_OFF) == state) { + // Clear blink segments + *blkmem = (uint8_t)(*blkmem & ~bitmask); + } + + if ( (state | BLINK_ON) == state) { + // Set blink segments + *blkmem = (uint8_t)(*blkmem | bits); + } } /*************************************************************************** @@ -382,184 +382,184 @@ static void write_lcd_mem(uint8_t *segmem, uint8_t *blkmem, **************************************************************************/ /* - lcd_screens_create() + lcd_screens_create() */ void lcd_screens_create(uint8_t nr) { - /* allocate memory */ - display_nrscreens = nr; - display_screens = malloc(sizeof(struct lcd_screen) * nr); - - /* the first screen is the active one */ - display_activescr = 0; - display_screens[0].segmem = LCD_SEG_MEM; - display_screens[0].blkmem = LCD_BLK_MEM; - - /* allocate mem for the remaining and copy real screen over */ - uint8_t i = 1; - for (; i>= 4; - digits--; - } while (n > 0); - } else { - do { - sprintf_str[j--] = n % 10 + '0'; - n /= 10; - digits--; - } while (n > 0); - } - - /* pad the remaining */ - while (digits > 0) { - sprintf_str[j--] = zpad; - digits--; - } - - j = j1; - } - - return sprintf_str; + int8_t i = 0; + int8_t j = 0; + + while (1) { + /* copy chars until end of string or a int substitution is found */ + while (fmt[i] != '%') { + if (fmt[i] == '\0' || j == SPRINTF_STR_LEN - 2) { + sprintf_str[j] = '\0'; + return sprintf_str; + } + sprintf_str[j++] = fmt[i++]; + } + i++; + + int8_t digits = 0; + int8_t zpad = ' '; + /* parse int substitution */ + while (fmt[i] != 's' && fmt[i] != 'u' && fmt[i] != 'x') { + if (fmt[i] == '0') + zpad = '0'; + else + digits = fmt[i] - '0'; + i++; + } + + /* show sign */ + if (fmt[i] == 's') { + if (n < 0) { + sprintf_str[j++] = '-'; + n = (~n) + 1; + } else + sprintf_str[j++] = ' '; + } + + j += digits - 1; + int8_t j1 = j + 1; + + /* convert int to string */ + if (fmt[i] == 'x') { + do { + sprintf_str[j--] = "0123456789ABCDEF"[n & 0x0F]; + n >>= 4; + digits--; + } while (n > 0); + } else { + do { + sprintf_str[j--] = n % 10 + '0'; + n /= 10; + digits--; + } while (n > 0); + } + + /* pad the remaining */ + while (digits > 0) { + sprintf_str[j--] = zpad; + digits--; + } + + j = j1; + } + + return sprintf_str; } // ************************************************************************************************* @@ -574,68 +574,68 @@ char *_sprintf(const char *fmt, int16_t n) { char *_itopct(uint32_t low,uint32_t high,uint32_t n) { - // Return "0" if the value is under the low - if (n < low) return (char *) " 0"; + // Return "0" if the value is under the low + if (n < low) return (char *) " 0"; - // Return "100" if the value is over the high - if (n > high) return (char *) "100"; + // Return "100" if the value is over the high + if (n > high) return (char *) "100"; - return _sprintf("%3u", (((n*100)-(low*100))/(high-low))); + return _sprintf("%3u", (((n*100)-(low*100))/(high-low))); } void display_symbol(uint8_t scr_nr, enum display_segment symbol, enum display_segstate state) { - if (symbol <= LCD_SEG_L2_DP) { - // Get LCD memory address for symbol from table - uint8_t *segmem = (uint8_t *)segments_lcdmem[symbol]; - uint8_t *blkmem = segmem + 0x20; - - if (display_screens) { - /* get offset */ - uint8_t offset = segmem - LCD_MEM_1; - - segmem = display_screens[scr_nr].segmem + offset; - blkmem = display_screens[scr_nr].blkmem + offset; - } - - // Get bits for symbol from table - uint8_t bits = segments_bitmask[symbol]; - - // Write LCD memory - // (bitmask for symbols equals bits) - write_lcd_mem(segmem, blkmem, bits, bits, state); - } + if (symbol <= LCD_SEG_L2_DP) { + // Get LCD memory address for symbol from table + uint8_t *segmem = (uint8_t *)segments_lcdmem[symbol]; + uint8_t *blkmem = segmem + 0x20; + + if (display_screens) { + /* get offset */ + uint8_t offset = segmem - LCD_MEM_1; + + segmem = display_screens[scr_nr].segmem + offset; + blkmem = display_screens[scr_nr].blkmem + offset; + } + + // Get bits for symbol from table + uint8_t bits = segments_bitmask[symbol]; + + // Write LCD memory + // (bitmask for symbols equals bits) + write_lcd_mem(segmem, blkmem, bits, bits, state); + } } void display_bits(uint8_t scr_nr, enum display_segment segment, uint8_t bits , enum display_segstate state) { - // Write to single 7-segment character - if ((segment >= LCD_SEG_L1_3) && (segment <= LCD_SEG_L2_DP)) { - // Get LCD memory address for segment from table - uint8_t *segmem = (uint8_t *)segments_lcdmem[segment]; - uint8_t *blkmem = segmem + 0x20; - - if (display_screens) { // safeguard - /* get offset */ - uint8_t offset = segmem - LCD_MEM_1; - - segmem = display_screens[scr_nr].segmem + offset; - blkmem = display_screens[scr_nr].blkmem + offset; - } - - // Get bitmask for character from table - uint8_t bitmask = segments_bitmask[segment]; - - // When addressing LINE2 7-segment characters need to swap high- and low-nibble, - // because LCD COM/SEG assignment is mirrored against LINE1 - if (segment >= LCD_SEG_L2_5) { - bits = SWAP_NIBBLE(bits); - } - - // Physically write to LCD memory - write_lcd_mem(segmem, blkmem, bits, bitmask, state); - } + // Write to single 7-segment character + if ((segment >= LCD_SEG_L1_3) && (segment <= LCD_SEG_L2_DP)) { + // Get LCD memory address for segment from table + uint8_t *segmem = (uint8_t *)segments_lcdmem[segment]; + uint8_t *blkmem = segmem + 0x20; + + if (display_screens) { // safeguard + /* get offset */ + uint8_t offset = segmem - LCD_MEM_1; + + segmem = display_screens[scr_nr].segmem + offset; + blkmem = display_screens[scr_nr].blkmem + offset; + } + + // Get bitmask for character from table + uint8_t bitmask = segments_bitmask[segment]; + + // When addressing LINE2 7-segment characters need to swap high- and low-nibble, + // because LCD COM/SEG assignment is mirrored against LINE1 + if (segment >= LCD_SEG_L2_5) { + bits = SWAP_NIBBLE(bits); + } + + // Physically write to LCD memory + write_lcd_mem(segmem, blkmem, bits, bitmask, state); + } } void display_char(uint8_t scr_nr, enum display_segment segment, @@ -645,11 +645,11 @@ void display_char(uint8_t scr_nr, enum display_segment segment, // Get bits from font set if (chr >= LCD_FONT_START_CHAR && chr <= LCD_FONT_END_CHAR) { - // Use font set - bits = lcd_font[chr - LCD_FONT_START_CHAR]; + // Use font set + bits = lcd_font[chr - LCD_FONT_START_CHAR]; } else if (chr == 0x2D) { - // '-' not in font set - bits = BIT1; + // '-' not in font set + bits = BIT1; } // When addressing LCD_SEG_L2_5, need to convert ASCII '1' and 'L' to 1 bit, @@ -665,19 +665,19 @@ void display_chars(uint8_t scr_nr, char const * str, enum display_segstate state) { - uint8_t i = 0; - uint8_t len = (segments & 0x0f); - segments = 38 - (segments >> 4); - - for (; i < len; i++) { - /* stop if we find a null termination */ - if (str) { - if (str[i] == '\0') - return; - display_char(scr_nr, segments + i, str[i], state); - } else - display_char(scr_nr, segments + i, '8', state); - } + uint8_t i = 0; + uint8_t len = (segments & 0x0f); + segments = 38 - (segments >> 4); + + for (; i < len; i++) { + /* stop if we find a null termination */ + if (str) { + if (str[i] == '\0') + return; + display_char(scr_nr, segments + i, str[i], state); + } else + display_char(scr_nr, segments + i, '8', state); + } } // ************************************************************************************************* @@ -688,7 +688,7 @@ void display_chars(uint8_t scr_nr, // ************************************************************************************************* void start_blink(void) { - LCDBBLKCTL |= LCDBLKMOD0; + LCDBBLKCTL |= LCDBLKMOD0; } @@ -700,7 +700,7 @@ void start_blink(void) // ************************************************************************************************* void stop_blink(void) { - LCDBBLKCTL &= ~LCDBLKMOD0; + LCDBBLKCTL &= ~LCDBLKMOD0; } @@ -712,9 +712,5 @@ void stop_blink(void) // ************************************************************************************************* void clear_blink_mem(void) { - LCDBMEMCTL |= LCDCLRBM; + LCDBMEMCTL |= LCDCLRBM; } - - - - diff --git a/drivers/display.h b/drivers/display.h index dd3323f..c5e8d88 100644 --- a/drivers/display.h +++ b/drivers/display.h @@ -34,8 +34,8 @@ ****************************************************************************/ /*! - \file display.h - \brief openchronos-ng display driver + \file display.h + \brief openchronos-ng display driver */ #ifndef __DISPLAY_H__ @@ -44,154 +44,154 @@ #include "openchronos.h" /*! - \brief Enumeration of segment states + \brief Enumeration of segment states */ enum display_segstate { - SEG_OFF = 1u, /*!< turn selected segment bits to OFF */ - SEG_ON = 2u, /*!< turn selected segment bits to ON */ - SEG_SET = 3u, /*!< turn OFF all bits of segment, then turn ON only selected bits */ - BLINK_OFF = 4u, /*!< turn blinking OFF on selected segment bits */ - BLINK_ON = 8u, /*!< turn blinking ON on selected segment bits */ - BLINK_SET = 12u /*!< turn blinking OFF on all bits of segment, then turn blinking ON on only selected bits */ + SEG_OFF = 1u, /*!< turn selected segment bits to OFF */ + SEG_ON = 2u, /*!< turn selected segment bits to ON */ + SEG_SET = 3u, /*!< turn OFF all bits of segment, then turn ON only selected bits */ + BLINK_OFF = 4u, /*!< turn blinking OFF on selected segment bits */ + BLINK_ON = 8u, /*!< turn blinking ON on selected segment bits */ + BLINK_SET = 12u /*!< turn blinking OFF on all bits of segment, then turn blinking ON on only selected bits */ }; /*! - \brief Enumeration of all ez430 chronos LCD segments + \brief Enumeration of all ez430 chronos LCD segments */ enum display_segment { - /* Symbols for Line1 */ - LCD_SYMB_AM = 0, /*!< AM symbol segment */ /* You must also set LCD_SYMB_PM to get full LCD_SYMB_AM */ - LCD_SYMB_PM = 1, /*!< PM symbol segment */ - LCD_SYMB_ARROW_UP = 2, /*!< little up arrow symbol segment */ - LCD_SYMB_ARROW_DOWN = 3, /*!< little down arrow symbol segment */ - LCD_SYMB_PERCENT = 4, /*!< percent symbol segment */ - - /* Symbols for Line2 */ - LCD_SYMB_TOTAL = 5, /*!< TOTAL symbol segment */ - LCD_SYMB_AVERAGE = 6, /*!< AVG symbol segment */ - LCD_SYMB_MAX = 7, /*!< MAX symbol segment */ - LCD_SYMB_BATTERY = 8, /*!< BATT symbol segment */ - - /* Units for Line1 */ - LCD_UNIT_L1_FT = 9, /*!< FT symbol segment */ - LCD_UNIT_L1_K = 10, /*!< K symbol segment */ - LCD_UNIT_L1_M = 11, /*!< M symbol segment */ - LCD_UNIT_L1_I = 12, /*!< I symbol segment */ - LCD_UNIT_L1_PER_S = 13, /*!< /s symbol segment */ - LCD_UNIT_L1_PER_H = 14, /*!< /h symbol segment */ - LCD_UNIT_L1_DEGREE = 15, /*!< º symbol segment */ - - /* Units for Line2 */ - LCD_UNIT_L2_KCAL = 16, /*!< kcal symbol segment */ - LCD_UNIT_L2_KM = 17, /*!< Km symbol segment */ - LCD_UNIT_L2_MI = 18, /*!< MI symbol segment */ - - /* Icons */ - LCD_ICON_HEART = 19, /*!< HEART symbol segment */ - LCD_ICON_STOPWATCH = 20, /*!< STOPWATCH symbol segment */ - LCD_ICON_RECORD = 21, /*!< RECORD symbol segment */ - LCD_ICON_ALARM = 22, /*!< ALARM symbol segment */ - LCD_ICON_BEEPER1 = 23, /*!< segment 1 of ((( symbol */ - LCD_ICON_BEEPER2 = 24, /*!< segment 2 of ((( symbol */ - LCD_ICON_BEEPER3 = 25, /*!< segment 3 of ((( symbol */ - - /* Line1 7-segments */ - LCD_SEG_L1_3 = 26, /*!< line1, 4th segment */ - LCD_SEG_L1_2 = 27, /*!< line1, 3rd segment */ - LCD_SEG_L1_1 = 28, /*!< line1, 2nd segment */ - LCD_SEG_L1_0 = 29, /*!< line1, 1st segment */ - LCD_SEG_L1_COL = 30, /*!< line1, : segment */ - LCD_SEG_L1_DP1 = 31, /*!< line1, comma between segment 2 and 3 */ - LCD_SEG_L1_DP0 = 32, /*!< line1, comma between segment 1 and 2 */ - - /* Line2 7-segments */ - LCD_SEG_L2_5 = 33, /*!< line2, 6th segment */ /* Only half a segment */ - LCD_SEG_L2_4 = 34, /*!< line2, 5th segment */ - LCD_SEG_L2_3 = 35, /*!< line2, 4th segment */ - LCD_SEG_L2_2 = 36, /*!< line2, 3rd segment */ - LCD_SEG_L2_1 = 37, /*!< line2, 2nd segment */ - LCD_SEG_L2_0 = 38, /*!< line2, 1st segment */ - LCD_SEG_L2_COL1 = 39, /*!< line2, 2nd : segment */ - LCD_SEG_L2_COL0 = 40, /*!< line2, 1st : segment */ - LCD_SEG_L2_DP = 41, /*!< line2, comma between segment 2 and 3 */ + /* Symbols for Line1 */ + LCD_SYMB_AM = 0, /*!< AM symbol segment */ /* You must also set LCD_SYMB_PM to get full LCD_SYMB_AM */ + LCD_SYMB_PM = 1, /*!< PM symbol segment */ + LCD_SYMB_ARROW_UP = 2, /*!< little up arrow symbol segment */ + LCD_SYMB_ARROW_DOWN = 3, /*!< little down arrow symbol segment */ + LCD_SYMB_PERCENT = 4, /*!< percent symbol segment */ + + /* Symbols for Line2 */ + LCD_SYMB_TOTAL = 5, /*!< TOTAL symbol segment */ + LCD_SYMB_AVERAGE = 6, /*!< AVG symbol segment */ + LCD_SYMB_MAX = 7, /*!< MAX symbol segment */ + LCD_SYMB_BATTERY = 8, /*!< BATT symbol segment */ + + /* Units for Line1 */ + LCD_UNIT_L1_FT = 9, /*!< FT symbol segment */ + LCD_UNIT_L1_K = 10, /*!< K symbol segment */ + LCD_UNIT_L1_M = 11, /*!< M symbol segment */ + LCD_UNIT_L1_I = 12, /*!< I symbol segment */ + LCD_UNIT_L1_PER_S = 13, /*!< /s symbol segment */ + LCD_UNIT_L1_PER_H = 14, /*!< /h symbol segment */ + LCD_UNIT_L1_DEGREE = 15, /*!< º symbol segment */ + + /* Units for Line2 */ + LCD_UNIT_L2_KCAL = 16, /*!< kcal symbol segment */ + LCD_UNIT_L2_KM = 17, /*!< Km symbol segment */ + LCD_UNIT_L2_MI = 18, /*!< MI symbol segment */ + + /* Icons */ + LCD_ICON_HEART = 19, /*!< HEART symbol segment */ + LCD_ICON_STOPWATCH = 20, /*!< STOPWATCH symbol segment */ + LCD_ICON_RECORD = 21, /*!< RECORD symbol segment */ + LCD_ICON_ALARM = 22, /*!< ALARM symbol segment */ + LCD_ICON_BEEPER1 = 23, /*!< segment 1 of ((( symbol */ + LCD_ICON_BEEPER2 = 24, /*!< segment 2 of ((( symbol */ + LCD_ICON_BEEPER3 = 25, /*!< segment 3 of ((( symbol */ + + /* Line1 7-segments */ + LCD_SEG_L1_3 = 26, /*!< line1, 4th segment */ + LCD_SEG_L1_2 = 27, /*!< line1, 3rd segment */ + LCD_SEG_L1_1 = 28, /*!< line1, 2nd segment */ + LCD_SEG_L1_0 = 29, /*!< line1, 1st segment */ + LCD_SEG_L1_COL = 30, /*!< line1, : segment */ + LCD_SEG_L1_DP1 = 31, /*!< line1, comma between segment 2 and 3 */ + LCD_SEG_L1_DP0 = 32, /*!< line1, comma between segment 1 and 2 */ + + /* Line2 7-segments */ + LCD_SEG_L2_5 = 33, /*!< line2, 6th segment */ /* Only half a segment */ + LCD_SEG_L2_4 = 34, /*!< line2, 5th segment */ + LCD_SEG_L2_3 = 35, /*!< line2, 4th segment */ + LCD_SEG_L2_2 = 36, /*!< line2, 3rd segment */ + LCD_SEG_L2_1 = 37, /*!< line2, 2nd segment */ + LCD_SEG_L2_0 = 38, /*!< line2, 1st segment */ + LCD_SEG_L2_COL1 = 39, /*!< line2, 2nd : segment */ + LCD_SEG_L2_COL0 = 40, /*!< line2, 1st : segment */ + LCD_SEG_L2_DP = 41, /*!< line2, comma between segment 2 and 3 */ }; /*! - \brief Enumeration of LCD segment arrays - \details The LCD_SEG_L1_3_2 member means the segments on line 1 from position 3 to 2 (inclusive). Segments are numbered from right to left. - \sa #display_chars() + \brief Enumeration of LCD segment arrays + \details The LCD_SEG_L1_3_2 member means the segments on line 1 from position 3 to 2 (inclusive). Segments are numbered from right to left. + \sa #display_chars() */ enum display_segment_array { - /* Line1 7-segment arrays */ - LCD_SEG_L1_3_2 = 0xc2, /*!< line1, segments 3-2 */ - LCD_SEG_L1_3_1 = 0xc3, /*!< line1, segments 3-1 */ - LCD_SEG_L1_3_0 = 0xc4, /*!< line1, segments 3-0 */ - LCD_SEG_L1_2_1 = 0xb2, /*!< line1, segments 2-1 */ - LCD_SEG_L1_2_0 = 0xb3, /*!< line1, segments 2-0 */ - LCD_SEG_L1_1_0 = 0xa2, /*!< line1, segments 1-0 */ - - /* Line2 7-segment arrays */ - LCD_SEG_L2_5_4 = 0x52, /*!< line2, segments 5-4 */ - LCD_SEG_L2_5_3 = 0x53, /*!< line2, segments 5-3 */ - LCD_SEG_L2_5_2 = 0x54, /*!< line2, segments 3-2 */ - LCD_SEG_L2_5_1 = 0x55, /*!< line2, segments 3-1 */ - LCD_SEG_L2_5_0 = 0x56, /*!< line2, segments 1-0 */ - LCD_SEG_L2_4_3 = 0x42, /*!< line2, segments 4-3 */ - LCD_SEG_L2_4_2 = 0x43, /*!< line2, segments 4-2 */ - LCD_SEG_L2_4_1 = 0x44, /*!< line2, segments 4-1 */ - LCD_SEG_L2_4_0 = 0x45, /*!< line2, segments 4-0 */ - LCD_SEG_L2_3_2 = 0x32, /*!< line2, segments 3-2 */ - LCD_SEG_L2_3_1 = 0x33, /*!< line2, segments 3-1 */ - LCD_SEG_L2_3_0 = 0x34, /*!< line2, segments 3-0 */ - LCD_SEG_L2_2_1 = 0x22, /*!< line2, segments 2-1 */ - LCD_SEG_L2_2_0 = 0x23, /*!< line2, segments 2-0 */ - LCD_SEG_L2_1_0 = 0x12, /*!< line2, segments 1-0 */ + /* Line1 7-segment arrays */ + LCD_SEG_L1_3_2 = 0xc2, /*!< line1, segments 3-2 */ + LCD_SEG_L1_3_1 = 0xc3, /*!< line1, segments 3-1 */ + LCD_SEG_L1_3_0 = 0xc4, /*!< line1, segments 3-0 */ + LCD_SEG_L1_2_1 = 0xb2, /*!< line1, segments 2-1 */ + LCD_SEG_L1_2_0 = 0xb3, /*!< line1, segments 2-0 */ + LCD_SEG_L1_1_0 = 0xa2, /*!< line1, segments 1-0 */ + + /* Line2 7-segment arrays */ + LCD_SEG_L2_5_4 = 0x52, /*!< line2, segments 5-4 */ + LCD_SEG_L2_5_3 = 0x53, /*!< line2, segments 5-3 */ + LCD_SEG_L2_5_2 = 0x54, /*!< line2, segments 3-2 */ + LCD_SEG_L2_5_1 = 0x55, /*!< line2, segments 3-1 */ + LCD_SEG_L2_5_0 = 0x56, /*!< line2, segments 1-0 */ + LCD_SEG_L2_4_3 = 0x42, /*!< line2, segments 4-3 */ + LCD_SEG_L2_4_2 = 0x43, /*!< line2, segments 4-2 */ + LCD_SEG_L2_4_1 = 0x44, /*!< line2, segments 4-1 */ + LCD_SEG_L2_4_0 = 0x45, /*!< line2, segments 4-0 */ + LCD_SEG_L2_3_2 = 0x32, /*!< line2, segments 3-2 */ + LCD_SEG_L2_3_1 = 0x33, /*!< line2, segments 3-1 */ + LCD_SEG_L2_3_0 = 0x34, /*!< line2, segments 3-0 */ + LCD_SEG_L2_2_1 = 0x22, /*!< line2, segments 2-1 */ + LCD_SEG_L2_2_0 = 0x23, /*!< line2, segments 2-0 */ + LCD_SEG_L2_1_0 = 0x12, /*!< line2, segments 1-0 */ }; /*! - \brief Virtual LCD screen - \sa #lcd_screens_create() + \brief Virtual LCD screen + \sa #lcd_screens_create() */ struct lcd_screen { - uint8_t *segmem; /*!< pointer to segment memory location */ - uint8_t *blkmem; /*!< pointer to blinking memory location */ + uint8_t *segmem; /*!< pointer to segment memory location */ + uint8_t *blkmem; /*!< pointer to blinking memory location */ }; /*! - \brief Creates virtual screens - \details Virtual screens are used to display data outside of the real screen. After creating nr number of screens, you can select which screen to write data to using the scr_nr argument available in any of the display functions:
- #display_symbol()
- #display_char()
- #display_chars()
- #display_clear()
- - After creating the virtual screens using this function, the screen 0 is always selected as the active screen. This means that any writes to screen 0 will actually be imediately displayed on the real screen, while writes to other screens will be saved until lcd_screen_activate() is called. - \note Each virtual screen takes 24bytes of memory. It is less than the code that you would actually need to write to handle the cases where these functions are meant to be used. However, RAM memory on the ez430 chronos is limited too so don't use a bazilion of screens. - \note Never, ever forget to destroy the created screens using lcd_screens_destroy() ! - \sa lcd_screens_destroy(), lcd_screen_activate() + \brief Creates virtual screens + \details Virtual screens are used to display data outside of the real screen. After creating nr number of screens, you can select which screen to write data to using the scr_nr argument available in any of the display functions:
+ #display_symbol()
+ #display_char()
+ #display_chars()
+ #display_clear()
+ + After creating the virtual screens using this function, the screen 0 is always selected as the active screen. This means that any writes to screen 0 will actually be imediately displayed on the real screen, while writes to other screens will be saved until lcd_screen_activate() is called. + \note Each virtual screen takes 24bytes of memory. It is less than the code that you would actually need to write to handle the cases where these functions are meant to be used. However, RAM memory on the ez430 chronos is limited too so don't use a bazilion of screens. + \note Never, ever forget to destroy the created screens using lcd_screens_destroy() ! + \sa lcd_screens_destroy(), lcd_screen_activate() */ void lcd_screens_create( - uint8_t nr /*!< the number of screens to create */ -); + uint8_t nr /*!< the number of screens to create */ + ); /*! - \brief Destroys all virtual screen - \details Destroys all #lcd_screen created by #lcd_screens_create() + \brief Destroys all virtual screen + \details Destroys all #lcd_screen created by #lcd_screens_create() */ void lcd_screens_destroy(void); uint8_t get_active_lcd_screen_nr(void); /*! - \brief Activates a virtual screen - \details Virtual screens are used to display data outside of the real screen. See lcd_screens_create() on how to create virtual screens.
- This function selects the active screen. The active screen is the screen where any writes to it will be imediately displayed in the real screen. - \note If you set the scr_nr to 0xff, the next screen will be automatically activated. - \sa lcd_screens_destroy(), lcd_screens_create() + \brief Activates a virtual screen + \details Virtual screens are used to display data outside of the real screen. See lcd_screens_create() on how to create virtual screens.
+ This function selects the active screen. The active screen is the screen where any writes to it will be imediately displayed in the real screen. + \note If you set the scr_nr to 0xff, the next screen will be automatically activated. + \sa lcd_screens_destroy(), lcd_screens_create() */ void lcd_screen_activate( - uint8_t scr_nr /*!< the screen number to activate, or 0xff */ -); + uint8_t scr_nr /*!< the screen number to activate, or 0xff */ + ); /* Not to be used by modules */ void start_blink(void); @@ -201,164 +201,164 @@ void clear_blink_mem(void); void fill_display(uint8_t scr_nr, uint8_t value); /*! - \brief Clears the screen - \details Clears the screen as instructed by line. If no virtual screens are created, the argument scr_nr is ignored, otherwise it selects which screen the operation will affect. + \brief Clears the screen + \details Clears the screen as instructed by line. If no virtual screens are created, the argument scr_nr is ignored, otherwise it selects which screen the operation will affect. */ void display_clear( - uint8_t scr_nr, /*!< the virtual screen number to clear */ - uint8_t line /*!< If zero, clears the entire screen (symbols and lines).
If one, clears the first line.
If two, clears the second line. */ -); + uint8_t scr_nr, /*!< the virtual screen number to clear */ + uint8_t line /*!< If zero, clears the entire screen (symbols and lines).
If one, clears the first line.
If two, clears the second line. */ + ); /* - \brief Display a custom collection of segments - \details Changes the state of segment state according to user specified bits. If no virtual screens are created, the argument scr_nr is ignored, otherwise it selects which screen the operation will affect. - \sa #display_char() + \brief Display a custom collection of segments + \details Changes the state of segment state according to user specified bits. If no virtual screens are created, the argument scr_nr is ignored, otherwise it selects which screen the operation will affect. + \sa #display_char() */ void display_bits( - uint8_t scr_nr, /*!< the virtual screen number where to display */ - enum display_segment segment, /*!< A segment */ - uint8_t bits, /*!< The bits of the segment */ - enum display_segstate state /*!< A bitfield with state operations to be performed on the segment */ -); + uint8_t scr_nr, /*!< the virtual screen number where to display */ + enum display_segment segment, /*!< A segment */ + uint8_t bits, /*!< The bits of the segment */ + enum display_segstate state /*!< A bitfield with state operations to be performed on the segment */ + ); /*! - \brief Displays a single character - \details Changes the state of segment state according to bits calculated from chr. If no virtual screens are created, the argument scr_nr is ignored, otherwise it selects which screen the operation will affect. - - For example, the following line:
- \code - display_char(0, LCD_SEG_L1_3, 'C', SEG_SET);
- \endcode - Changes the bits of the 4th segment (from the right) of first line to show a 'C' character. The 'C' character is shown in the real screen. - - Another but a little more complex example:
- \code - // changes the bits of the 4th segment (from the right) of first line to show the '1' character in the real screen. - display_char(0, LCD_SEG_L1_3, '1', SEG_SET); - - // makes all bits of the segment to blink. because only the bits corresponding to the '1' character are being shown, only the displayed '1' blinks. - display_char(0, LCD_SEG_L1_3, '8', BLINK_ON); - - // changes the bits of the segment to show the '8' character. this operation doesn't change the blinking bits, so the displayed '8' will blink. - display_char(0, LCD_SEG_L1_3, '8', SEG_SET); - - // turns off blinking for the bits corresponding to the '-' character. In this case because the bits of '8' were blinking, turning off '-' will make the bits of '0' continue blinking, while the '-' remains static. - display_char(0, LCD_SEG_L1_3, '-', BLINK_OFF); - \endcode - \sa #display_chars() + \brief Displays a single character + \details Changes the state of segment state according to bits calculated from chr. If no virtual screens are created, the argument scr_nr is ignored, otherwise it selects which screen the operation will affect. + + For example, the following line:
+ \code + display_char(0, LCD_SEG_L1_3, 'C', SEG_SET);
+ \endcode + Changes the bits of the 4th segment (from the right) of first line to show a 'C' character. The 'C' character is shown in the real screen. + + Another but a little more complex example:
+ \code + // changes the bits of the 4th segment (from the right) of first line to show the '1' character in the real screen. + display_char(0, LCD_SEG_L1_3, '1', SEG_SET); + + // makes all bits of the segment to blink. because only the bits corresponding to the '1' character are being shown, only the displayed '1' blinks. + display_char(0, LCD_SEG_L1_3, '8', BLINK_ON); + + // changes the bits of the segment to show the '8' character. this operation doesn't change the blinking bits, so the displayed '8' will blink. + display_char(0, LCD_SEG_L1_3, '8', SEG_SET); + + // turns off blinking for the bits corresponding to the '-' character. In this case because the bits of '8' were blinking, turning off '-' will make the bits of '0' continue blinking, while the '-' remains static. + display_char(0, LCD_SEG_L1_3, '-', BLINK_OFF); + \endcode + \sa #display_chars() */ void display_char( - uint8_t scr_nr, /*!< the virtual screen number where to display */ - enum display_segment segment, /*!< A segment */ - char chr, /*!< The character to be displayed */ - enum display_segstate state /*!< A bitfield with state operations to be performed on the segment */ -); + uint8_t scr_nr, /*!< the virtual screen number where to display */ + enum display_segment segment, /*!< A segment */ + char chr, /*!< The character to be displayed */ + enum display_segstate state /*!< A bitfield with state operations to be performed on the segment */ + ); /*! - \brief Displays several consecutive characters - \details Smiliar to #display_char() except it works with a vector of chars. + \brief Displays several consecutive characters + \details Smiliar to #display_char() except it works with a vector of chars. - Example:
- \code - // changes the bits of the 4th to 1st segments (from the right) of the first line to show the "4321" string in the real screen. - display_chars(0, LCD_SEG_L1_3_0, "4321", SEG_SET); + Example:
+ \code + // changes the bits of the 4th to 1st segments (from the right) of the first line to show the "4321" string in the real screen. + display_chars(0, LCD_SEG_L1_3_0, "4321", SEG_SET); - // makes all bits of the first three segments to blink. because only the bits corresponding to the "4321" characters are being shown, only the first three displayed "432" segments blink. - display_chars(0, LCD_SEG_L1_3_0, "888 ", BLINK_ON); + // makes all bits of the first three segments to blink. because only the bits corresponding to the "4321" characters are being shown, only the first three displayed "432" segments blink. + display_chars(0, LCD_SEG_L1_3_0, "888 ", BLINK_ON); - // changes the bits of the segments to show the "8888" string. this operation doesn't change the blinking bits, so the first three displayed "888" segments will blink, while the last '8' segment is static. - display_chars(0, LCD_SEG_L1_3_0, "8888", SEG_SET); + // changes the bits of the segments to show the "8888" string. this operation doesn't change the blinking bits, so the first three displayed "888" segments will blink, while the last '8' segment is static. + display_chars(0, LCD_SEG_L1_3_0, "8888", SEG_SET); - // turns off blinking for the bits corresponding to the "----" characters. In this case because the bits of "888 " were blinking, turning off "----" will actually set the blinking bits to "000 ". Because the "8888" string is being displayed, only the first three "000" bits will blink, the first three "---" bits will remain static and the last segment remains static. - display_chars(0, LCD_SEG_L1_3_0, "----", BLINK_OFF); - \endcode - Also, passing NULL as the str argument is equivalent of passing a vector of '8' characters. Consider the previous example, where the string "8888" can equivalently be replaced with NULL. + // turns off blinking for the bits corresponding to the "----" characters. In this case because the bits of "888 " were blinking, turning off "----" will actually set the blinking bits to "000 ". Because the "8888" string is being displayed, only the first three "000" bits will blink, the first three "---" bits will remain static and the last segment remains static. + display_chars(0, LCD_SEG_L1_3_0, "----", BLINK_OFF); + \endcode + Also, passing NULL as the str argument is equivalent of passing a vector of '8' characters. Consider the previous example, where the string "8888" can equivalently be replaced with NULL. - \note See #_sprintf() on how to convert decimals into a string. - \sa #display_char(), #_sprintf() + \note See #_sprintf() on how to convert decimals into a string. + \sa #display_char(), #_sprintf() */ void display_chars( - uint8_t scr_nr, /*!< the virtual screen number where to display */ - enum display_segment_array segments, /*!< A segment array */ - char const * str, /*!< A pointer to a vector of chars to be displayed */ - enum display_segstate state /*!< A bitfield with state operations to be performed on the segment */ -); + uint8_t scr_nr, /*!< the virtual screen number where to display */ + enum display_segment_array segments, /*!< A segment array */ + char const * str, /*!< A pointer to a vector of chars to be displayed */ + enum display_segstate state /*!< A bitfield with state operations to be performed on the segment */ + ); /*! - \brief Displays a symbol - \details Changes the state of the segment of symbol. If no virtual screens are created, the argument scr_nr is ignored, otherwise it selects which screen the operation will affect. - Example: - \code - // turns on the "heart" segment and make it blink - display_symbol(0, LCD_ICON_HEART, SEG_SET | BLINK_ON); - \endcode + \brief Displays a symbol + \details Changes the state of the segment of symbol. If no virtual screens are created, the argument scr_nr is ignored, otherwise it selects which screen the operation will affect. + Example: + \code + // turns on the "heart" segment and make it blink + display_symbol(0, LCD_ICON_HEART, SEG_SET | BLINK_ON); + \endcode */ void display_symbol( - uint8_t scr_nr, /*!< the virtual screen number */ - enum display_segment symbol, /*!< the segment to display */ - enum display_segstate state /*!< A bitfield with state operations to be performed on the segment */ -); + uint8_t scr_nr, /*!< the virtual screen number */ + enum display_segment symbol, /*!< the segment to display */ + enum display_segstate state /*!< A bitfield with state operations to be performed on the segment */ + ); /*! - \brief pseudo printf function - \details Displays in screen scr_nr, at segments segments, the string containing the number n formatted according to fmt. This function is equivalent to calling display_chars(scr_nr, segments, _sprintf(fmt, n), SEG_SET). - \sa #display_chars, #_sprintf + \brief pseudo printf function + \details Displays in screen scr_nr, at segments segments, the string containing the number n formatted according to fmt. This function is equivalent to calling display_chars(scr_nr, segments, _sprintf(fmt, n), SEG_SET). + \sa #display_chars, #_sprintf */ -#define _printf(scr_nr, segments, fmt, n) \ - display_chars((scr_nr), (segments), _sprintf((fmt), (n)), SEG_SET) +#define _printf(scr_nr, segments, fmt, n) \ + display_chars((scr_nr), (segments), _sprintf((fmt), (n)), SEG_SET) /*! - \brief pseudo sprintf function - \details Returns a pointer to the string containing the number n formatted according to fmt. The format is NOT compatible with stdio's format. - Example: - \code - // returns " 8" - _sprintf("%2u", 8); + \brief pseudo sprintf function + \details Returns a pointer to the string containing the number n formatted according to fmt. The format is NOT compatible with stdio's format. + Example: + \code + // returns " 8" + _sprintf("%2u", 8); - // returns "0020" - _sprintf("%04u", 20); + // returns "0020" + _sprintf("%04u", 20); - // returns "-048" - _sprintf("%03s", -48); + // returns "-048" + _sprintf("%03s", -48); - // returns " 048" - _sprintf("%03s", 48); + // returns " 048" + _sprintf("%03s", 48); - // returns "0xff" - _sprintf("0x%02", 0xff); + // returns "0xff" + _sprintf("0x%02x", 0xff); - // returns "st1x" - _sprintf("st%1ux", 1) - \endcode + // returns "st1x" + _sprintf("st%1ux", 1) + \endcode - WARNING: You must always specify the number of digits or bad results will happen! "%u" formats are not allowed! + WARNING: You must always specify the number of digits or bad results will happen! "%u" formats are not allowed! - \return a pointer to a string + \return a pointer to a string */ char *_sprintf( - const char *fmt, /*!< the format specifier */ - int16_t n /*!< the number to be used in the format specifier */ -); + const char *fmt, /*!< the format specifier */ + int16_t n /*!< the number to be used in the format specifier */ + ); /*! - \brief Converts an integer from a range into a percent string between 0 and 100 - \details Takes the number n and returns a string representation of that number as a percent between low and high. The returned string is 3 characters long. - - Example: - \code - // this returns "4F" - uint8_t *s = _itoa(0x4F, 2, 0); - \endcode - \return a string representation of n + \brief Converts an integer from a range into a percent string between 0 and 100 + \details Takes the number n and returns a string representation of that number as a percent between low and high. The returned string is 3 characters long. + + Example: + \code + // this returns "4F" + uint8_t *s = _itoa(0x4F, 2, 0); + \endcode + \return a string representation of n */ char *_itopct( - uint32_t low, /*!< the 0% value */ - uint32_t high, /*!< the 100% value */ - uint32_t n -); + uint32_t low, /*!< the 0% value */ + uint32_t high, /*!< the 100% value */ + uint32_t n + ); #endif /* __DISPLAY_H__ */ diff --git a/drivers/dsp.c b/drivers/dsp.c index f167997..eb6f9a0 100644 --- a/drivers/dsp.c +++ b/drivers/dsp.c @@ -25,7 +25,7 @@ int16_t mult_scale16(int16_t a, int16_t b) { #define HALF ((int32_t)0x8000) - return (int16_t)(((int32_t)a * b + HALF) >> 16); + return (int16_t)(((int32_t)a * b + HALF) >> 16); } // ************************************************************************************************* @@ -38,11 +38,11 @@ int16_t mult_scale16(int16_t a, int16_t b) int16_t mult_scale15(int16_t a, int16_t b) { #define HALF ((int32_t)0x8000) - int32_t ff; - ff = ((int32_t)a * b); - // Note 1: The sequence of a separate << 1 and >>16 operation produces - // far more efficient compiled code than >> 15. - // Note 2: Combining the shift(s) with previous statement is not accepted by the compiler. - ff <<= 1; - return (int16_t)((ff + HALF) >> 16); + int32_t ff; + ff = ((int32_t)a * b); + // Note 1: The sequence of a separate << 1 and >>16 operation produces + // far more efficient compiled code than >> 15. + // Note 2: Combining the shift(s) with previous statement is not accepted by the compiler. + ff <<= 1; + return (int16_t)((ff + HALF) >> 16); } diff --git a/drivers/infomem.c b/drivers/infomem.c index 26897c5..0d24c22 100644 --- a/drivers/infomem.c +++ b/drivers/infomem.c @@ -18,12 +18,12 @@ void infomem_insert_delete_modify(uint16_t *start, uint16_t *data, uint8_t del_c void infomem_write_data(uint16_t *start, uint16_t *data, uint8_t count); uint16_t *infomem_get_app_addr(uint8_t identifier); -#define infomem_waitbusy() \ - while(1) \ - { \ - if(!(FCTL3 & BUSY)) \ - break; \ - } +#define infomem_waitbusy() \ + while(1) \ + { \ + if(!(FCTL3 & BUSY)) \ + break; \ + } // write one complete flash segment // FOR INTERNAL USE ONLY @@ -33,65 +33,65 @@ uint16_t *infomem_get_app_addr(uint8_t identifier); //erase 0: do not erase; 1: test if need to erase; 2: erase without test void infomem_write_flash_segment(uint16_t *start, uint16_t *data, uint8_t erase) { - int i; - - //check if we need to erase - if (erase == 1) { - for (i = 0; i < INFOMEM_SEGMENT_WORDS; i++) { - //we have to erase if the new data has bits 1 that are 0 already - if ((start[i] | data[i]) != start[i]) { - erase = 2; - break; - } - } - } + int i; + + //check if we need to erase + if (erase == 1) { + for (i = 0; i < INFOMEM_SEGMENT_WORDS; i++) { + //we have to erase if the new data has bits 1 that are 0 already + if ((start[i] | data[i]) != start[i]) { + erase = 2; + break; + } + } + } #ifdef USE_WATCHDOG - //hold watch dog timer - WDTCTL = (WDTCTL & 0xff) | WDTPW | WDTHOLD; + //hold watch dog timer + WDTCTL = (WDTCTL & 0xff) | WDTPW | WDTHOLD; #endif - infomem_waitbusy() + infomem_waitbusy() - //remove LOCK and LOCKA bit if needed (LOCKA is toggled if it is written as 1) - if (start == (uint16_t *)INFOMEM_A && (FCTL3 & LOCKA)) { - FCTL3 = FWKEY | LOCKA; - } else { - FCTL3 = FWKEY; - } + //remove LOCK and LOCKA bit if needed (LOCKA is toggled if it is written as 1) + if (start == (uint16_t *)INFOMEM_A && (FCTL3 & LOCKA)) { + FCTL3 = FWKEY | LOCKA; + } else { + FCTL3 = FWKEY; + } - //remove LOCKINFO bit - FCTL4 = FWKEY ; + //remove LOCKINFO bit + FCTL4 = FWKEY ; - if (erase == 2) { - FCTL1 = FWKEY | ERASE; - *start = 0; - infomem_waitbusy() - } + if (erase == 2) { + FCTL1 = FWKEY | ERASE; + *start = 0; + infomem_waitbusy() + } - //set long-word write mode - FCTL1 = FWKEY | BLKWRT; + //set long-word write mode + FCTL1 = FWKEY | BLKWRT; - //write long words if the new data is different from the old - for (i = 0; i < INFOMEM_SEGMENT_WORDS; i += 2) { - if (start[i] != data[i] || start[i + 1] != data[i + 1]) { - start[i ] = data[i ]; - start[i + 1] = data[i + 1]; - infomem_waitbusy() - } - } + //write long words if the new data is different from the old + for (i = 0; i < INFOMEM_SEGMENT_WORDS; i += 2) { + if (start[i] != data[i] || start[i + 1] != data[i + 1]) { + start[i ] = data[i ]; + start[i + 1] = data[i + 1]; + infomem_waitbusy() + } + } - //leave write mode - FCTL1 = FWKEY; - //set LOCKINFO bit - FCTL4 = FWKEY | (FCTL4 & 0xff) | LOCKINFO; + //leave write mode + FCTL1 = FWKEY; + //set LOCKINFO bit + FCTL4 = FWKEY | (FCTL4 & 0xff) | LOCKINFO; - //set LOCK bit - FCTL3 = FWKEY | (FCTL3 & 0xff) | LOCK; + //set LOCK bit + FCTL3 = FWKEY | (FCTL3 & 0xff) | LOCK; #ifdef USE_WATCHDOG - //restart and reset watchdog timer - WDTCTL = (WDTCTL & 0xff & ~WDTHOLD) | WDTPW | WDTCNTCL; + //restart and reset watchdog timer + WDTCTL = (WDTCTL & 0xff & ~WDTHOLD) | WDTPW | WDTCNTCL; #endif } @@ -99,7 +99,7 @@ void infomem_write_flash_segment(uint16_t *start, uint16_t *data, uint8_t erase) //write count words at address start void infomem_write_data(uint16_t *start, uint16_t *data, uint8_t count) { - infomem_insert_delete_modify(start, data, count, count, NULL, NULL, 0, sInfomem.startaddr + 3 + sInfomem.size, sInfomem.startaddr + 3 + sInfomem.maxsize); + infomem_insert_delete_modify(start, data, count, count, NULL, NULL, 0, sInfomem.startaddr + 3 + sInfomem.size, sInfomem.startaddr + 3 + sInfomem.maxsize); } // function to do nearly anything with memory @@ -115,132 +115,132 @@ void infomem_write_data(uint16_t *start, uint16_t *data, uint8_t count) // mod_addr are addresses AFTER the insert/delete void infomem_insert_delete_modify(uint16_t *start, uint16_t *data, uint8_t del_count, uint8_t ins_count, uint16_t **mod_addr, uint16_t *mod_data, uint8_t mod_count, uint16_t *free_start, uint16_t *free_stop) { - int i; - uint8_t next_mod; - int more = ins_count - del_count; - - //beginning of segment that is the first (address wise) to be modified - uint16_t *segment_first; - //beginning of the segment that is the last (address wise) to be modified - uint16_t *segment_last; - - //find first modified flash segment - if ((mod_count > 0) && (mod_addr[0] < start)) { - segment_first = (uint16_t *)((uint16_t) mod_addr[0] & ~(INFOMEM_SEGMENT_SIZE - 1)); - } else { - segment_first = (uint16_t *)((uint16_t) start & ~(INFOMEM_SEGMENT_SIZE - 1)); - } - - //find last modified flash segment - if (more == 0) { - if ((mod_count > 0) && (mod_addr[mod_count - 1] >= start + ins_count)) { - segment_last = (uint16_t *)((uint16_t) mod_addr[mod_count - 1] & ~(INFOMEM_SEGMENT_SIZE - 1)); - } else { - segment_last = (uint16_t *)((uint16_t)(start + ins_count - 1) & ~(INFOMEM_SEGMENT_SIZE - 1)); - } - } else if (more > 0) { - segment_last = (uint16_t *)((uint16_t)(free_start + more - 1) & ~(INFOMEM_SEGMENT_SIZE - 1)); - } else { //more<0 - segment_last = (uint16_t *)((uint16_t)(free_start - 1) & ~(INFOMEM_SEGMENT_SIZE - 1)); - } - - //we need buffer memory to store a flash page while it is erased and rewritten - uint16_t buf[INFOMEM_SEGMENT_WORDS]; - - //position of the newly to insert data relative to the beginning of the segment - int data_offset; - - //we insert data, so start with the last segment and make your way to the beginning - if (more > 0) { - //start with the last mod - next_mod = mod_count; - - //while we have not processed all modified flash segments - while (segment_first <= segment_last) { - data_offset = ((uint16_t)start - (uint16_t)segment_last) / 2; - - for (i = INFOMEM_SEGMENT_WORDS - 1; i >= 0; i--) { - //data we need to preserve - if ((segment_last + i) >= free_stop) { - buf[i] = segment_last[i]; - } - //data to change with single modify - else if (next_mod != 0 && (segment_last + i) == mod_addr[next_mod - 1]) { - buf[i] = mod_data[next_mod - 1]; - next_mod --; - } - //data we do not care about (leave erased) - else if ((segment_last + i) >= (free_start + more)) { - buf[i] = INFOMEM_ERASED_WORD; - } - //data not to change - else if ((segment_last + i) < start) { - buf[i] = segment_last[i]; - } - //data following the data we insert - else if ((segment_last + i) >= (start + ins_count)) { - buf[i] = segment_last[i - more]; - } - //data to insert - else { // if( (segment_last+i) >= start && (segment_last+i) < (start+ins_count) ) - if (data == NULL) { - buf[i] = INFOMEM_ERASED_WORD; - } else { - buf[i] = data[i - data_offset]; - } - } - } - - //write buffer to flash - infomem_write_flash_segment(segment_last, buf, 1); - //we have processed the last segment, process the next in the next loop run - segment_last -= INFOMEM_SEGMENT_WORDS; - } - } - //start with the first segment - else { //if more<0 - //start with the first mod - next_mod = 0; - - while (segment_first <= segment_last) { - data_offset = ((uint16_t)start - (uint16_t)segment_first) / 2; - - for (i = 0; i < INFOMEM_SEGMENT_WORDS; i++) { - //data we need to preserve - if ((segment_first + i) >= free_stop) { - buf[i] = segment_first[i]; - } - //data to change with single modify - else if (next_mod != mod_count && (segment_first + i) == mod_addr[next_mod]) { - buf[i] = mod_data[next_mod]; - next_mod++; - } - //data we do not care about (leave erased) - else if ((segment_first + i) >= (free_start + more)) { - buf[i] = INFOMEM_ERASED_WORD; - } - //data not to change - else if ((segment_first + i) < start) { - buf[i] = segment_first[i]; - } - //data following the data we insert - else if ((segment_first + i) >= (start + ins_count)) { - buf[i] = segment_first[i - more]; - } - //data to insert - else { // if( (segment_first+i) >= start && (segment_first+i) < (start+ins_count) ) - if (data == NULL) { - buf[i] = INFOMEM_ERASED_WORD; - } else { - buf[i] = data[i - data_offset]; - } - } - } - - infomem_write_flash_segment(segment_first, buf, 1); - segment_first += INFOMEM_SEGMENT_WORDS; - } - } + int i; + uint8_t next_mod; + int more = ins_count - del_count; + + //beginning of segment that is the first (address wise) to be modified + uint16_t *segment_first; + //beginning of the segment that is the last (address wise) to be modified + uint16_t *segment_last; + + //find first modified flash segment + if ((mod_count > 0) && (mod_addr[0] < start)) { + segment_first = (uint16_t *)((uint16_t) mod_addr[0] & ~(INFOMEM_SEGMENT_SIZE - 1)); + } else { + segment_first = (uint16_t *)((uint16_t) start & ~(INFOMEM_SEGMENT_SIZE - 1)); + } + + //find last modified flash segment + if (more == 0) { + if ((mod_count > 0) && (mod_addr[mod_count - 1] >= start + ins_count)) { + segment_last = (uint16_t *)((uint16_t) mod_addr[mod_count - 1] & ~(INFOMEM_SEGMENT_SIZE - 1)); + } else { + segment_last = (uint16_t *)((uint16_t)(start + ins_count - 1) & ~(INFOMEM_SEGMENT_SIZE - 1)); + } + } else if (more > 0) { + segment_last = (uint16_t *)((uint16_t)(free_start + more - 1) & ~(INFOMEM_SEGMENT_SIZE - 1)); + } else { //more<0 + segment_last = (uint16_t *)((uint16_t)(free_start - 1) & ~(INFOMEM_SEGMENT_SIZE - 1)); + } + + //we need buffer memory to store a flash page while it is erased and rewritten + uint16_t buf[INFOMEM_SEGMENT_WORDS]; + + //position of the newly to insert data relative to the beginning of the segment + int data_offset; + + //we insert data, so start with the last segment and make your way to the beginning + if (more > 0) { + //start with the last mod + next_mod = mod_count; + + //while we have not processed all modified flash segments + while (segment_first <= segment_last) { + data_offset = ((uint16_t)start - (uint16_t)segment_last) / 2; + + for (i = INFOMEM_SEGMENT_WORDS - 1; i >= 0; i--) { + //data we need to preserve + if ((segment_last + i) >= free_stop) { + buf[i] = segment_last[i]; + } + //data to change with single modify + else if (next_mod != 0 && (segment_last + i) == mod_addr[next_mod - 1]) { + buf[i] = mod_data[next_mod - 1]; + next_mod --; + } + //data we do not care about (leave erased) + else if ((segment_last + i) >= (free_start + more)) { + buf[i] = INFOMEM_ERASED_WORD; + } + //data not to change + else if ((segment_last + i) < start) { + buf[i] = segment_last[i]; + } + //data following the data we insert + else if ((segment_last + i) >= (start + ins_count)) { + buf[i] = segment_last[i - more]; + } + //data to insert + else { // if( (segment_last+i) >= start && (segment_last+i) < (start+ins_count) ) + if (data == NULL) { + buf[i] = INFOMEM_ERASED_WORD; + } else { + buf[i] = data[i - data_offset]; + } + } + } + + //write buffer to flash + infomem_write_flash_segment(segment_last, buf, 1); + //we have processed the last segment, process the next in the next loop run + segment_last -= INFOMEM_SEGMENT_WORDS; + } + } + //start with the first segment + else { //if more<0 + //start with the first mod + next_mod = 0; + + while (segment_first <= segment_last) { + data_offset = ((uint16_t)start - (uint16_t)segment_first) / 2; + + for (i = 0; i < INFOMEM_SEGMENT_WORDS; i++) { + //data we need to preserve + if ((segment_first + i) >= free_stop) { + buf[i] = segment_first[i]; + } + //data to change with single modify + else if (next_mod != mod_count && (segment_first + i) == mod_addr[next_mod]) { + buf[i] = mod_data[next_mod]; + next_mod++; + } + //data we do not care about (leave erased) + else if ((segment_first + i) >= (free_start + more)) { + buf[i] = INFOMEM_ERASED_WORD; + } + //data not to change + else if ((segment_first + i) < start) { + buf[i] = segment_first[i]; + } + //data following the data we insert + else if ((segment_first + i) >= (start + ins_count)) { + buf[i] = segment_first[i - more]; + } + //data to insert + else { // if( (segment_first+i) >= start && (segment_first+i) < (start+ins_count) ) + if (data == NULL) { + buf[i] = INFOMEM_ERASED_WORD; + } else { + buf[i] = data[i - data_offset]; + } + } + } + + infomem_write_flash_segment(segment_first, buf, 1); + segment_first += INFOMEM_SEGMENT_WORDS; + } + } } // ************************************************************************************************* @@ -253,23 +253,23 @@ void infomem_insert_delete_modify(uint16_t *start, uint16_t *data, uint8_t del_c // ************************************************************************************************* uint16_t *infomem_get_app_addr(uint8_t identifier) { - //start at the first word of payload - uint16_t *addr = sInfomem.startaddr + 2; - - //while we have not reached the end - while (addr < sInfomem.startaddr + 2 + sInfomem.size) { - //application found, return address - if (((uint8_t *)addr)[0] == identifier) { - return addr; - } - //step to header of next application - else { - addr += ((uint8_t *)addr)[1] + 1; - } - } - - //application not found - return NULL; + //start at the first word of payload + uint16_t *addr = sInfomem.startaddr + 2; + + //while we have not reached the end + while (addr < sInfomem.startaddr + 2 + sInfomem.size) { + //application found, return address + if (((uint8_t *)addr)[0] == identifier) { + return addr; + } + //step to header of next application + else { + addr += ((uint8_t *)addr)[1] + 1; + } + } + + //application not found + return NULL; } // ************************************************************************************************* @@ -282,71 +282,71 @@ uint16_t *infomem_get_app_addr(uint8_t identifier) // ************************************************************************************************* int16_t infomem_ready() { - uint8_t found_beg = 0; - - //already checked, trust that and just return size - if (sInfomem.sane == INFOMEM_SANE) { - return sInfomem.size; - } - - //if address is already set and in right range, look if it is correct, otherwise reset it - if ((((uint16_t)(sInfomem.startaddr)) >= INFOMEM_START) && (((uint16_t)(sInfomem.startaddr)) < (INFOMEM_START + 4 * INFOMEM_SEGMENT_SIZE))) { - if (*(sInfomem.startaddr) == INFOMEM_IDENTIFIER) { - found_beg = 1; - } else { - sInfomem.startaddr = NULL; - } - } - - //search for identifier word of information memory by looping over memory - if (found_beg == 0) { - uint16_t *addr; - - for (addr = (uint16_t *)INFOMEM_START; addr < (uint16_t *)(INFOMEM_START + 4 * INFOMEM_SEGMENT_SIZE); addr++) { - if (*addr == INFOMEM_IDENTIFIER) { - sInfomem.startaddr = addr; - found_beg = 1; - break; - } - } - } - - //give up searching - if (found_beg == 0) { - return -2; - } - - //read size and maxsize - sInfomem.size = ((uint8_t *)(sInfomem.startaddr))[2]; - sInfomem.maxsize = ((uint8_t *)(sInfomem.startaddr))[3]; - - //check size and maxsize for plausibility - if (sInfomem.size > sInfomem.maxsize || sInfomem.maxsize > (INFOMEM_START + 4 * INFOMEM_SEGMENT_SIZE - 6 - (uint16_t)sInfomem.startaddr) / 2) { - return -3; - } - - //loop through applications towards the end of the memory - uint16_t *addr = sInfomem.startaddr + 2; - - while (addr < sInfomem.startaddr + 2 + sInfomem.size) { - addr += ((uint8_t *)addr)[1] + 1; - } - - //return when the sum of the application sizes does not match the total size - if (addr != sInfomem.startaddr + sInfomem.size + 2) { - return -4; - } - - - //check if terminator word is in place - if (sInfomem.startaddr[sInfomem.size + 2] != INFOMEM_TERMINATOR) { - return -5; - } - - //exerything seems to be OK - sInfomem.sane = INFOMEM_SANE; - sInfomem.not_lock = 1; - return sInfomem.size; + uint8_t found_beg = 0; + + //already checked, trust that and just return size + if (sInfomem.sane == INFOMEM_SANE) { + return sInfomem.size; + } + + //if address is already set and in right range, look if it is correct, otherwise reset it + if ((((uint16_t)(sInfomem.startaddr)) >= INFOMEM_START) && (((uint16_t)(sInfomem.startaddr)) < (INFOMEM_START + 4 * INFOMEM_SEGMENT_SIZE))) { + if (*(sInfomem.startaddr) == INFOMEM_IDENTIFIER) { + found_beg = 1; + } else { + sInfomem.startaddr = NULL; + } + } + + //search for identifier word of information memory by looping over memory + if (found_beg == 0) { + uint16_t *addr; + + for (addr = (uint16_t *)INFOMEM_START; addr < (uint16_t *)(INFOMEM_START + 4 * INFOMEM_SEGMENT_SIZE); addr++) { + if (*addr == INFOMEM_IDENTIFIER) { + sInfomem.startaddr = addr; + found_beg = 1; + break; + } + } + } + + //give up searching + if (found_beg == 0) { + return -2; + } + + //read size and maxsize + sInfomem.size = ((uint8_t *)(sInfomem.startaddr))[2]; + sInfomem.maxsize = ((uint8_t *)(sInfomem.startaddr))[3]; + + //check size and maxsize for plausibility + if (sInfomem.size > sInfomem.maxsize || sInfomem.maxsize > (INFOMEM_START + 4 * INFOMEM_SEGMENT_SIZE - 6 - (uint16_t)sInfomem.startaddr) / 2) { + return -3; + } + + //loop through applications towards the end of the memory + uint16_t *addr = sInfomem.startaddr + 2; + + while (addr < sInfomem.startaddr + 2 + sInfomem.size) { + addr += ((uint8_t *)addr)[1] + 1; + } + + //return when the sum of the application sizes does not match the total size + if (addr != sInfomem.startaddr + sInfomem.size + 2) { + return -4; + } + + + //check if terminator word is in place + if (sInfomem.startaddr[sInfomem.size + 2] != INFOMEM_TERMINATOR) { + return -5; + } + + //exerything seems to be OK + sInfomem.sane = INFOMEM_SANE; + sInfomem.not_lock = 1; + return sInfomem.size; } @@ -362,44 +362,44 @@ int16_t infomem_ready() // ************************************************************************************************* int16_t infomem_init(uint16_t start, uint16_t end) { - if (sInfomem.sane == INFOMEM_SANE) { - return -1; - } + if (sInfomem.sane == INFOMEM_SANE) { + return -1; + } - uint16_t numwords = (end - start) / 2; + uint16_t numwords = (end - start) / 2; - //check if address boundaries are usable - if (start & 0x1 || end & 0x1 || end < start || numwords < 10 || start < INFOMEM_START || end > INFOMEM_START + 4 * INFOMEM_SEGMENT_SIZE) { - return -2; - } + //check if address boundaries are usable + if (start & 0x1 || end & 0x1 || end < start || numwords < 10 || start < INFOMEM_START || end > INFOMEM_START + 4 * INFOMEM_SEGMENT_SIZE) { + return -2; + } - int i; + int i; - //check if memory area is empty - for (i = 0; i < numwords; i++) { - if (((uint16_t *)start)[i] != INFOMEM_ERASED_WORD) { - return -3; - } - } + //check if memory area is empty + for (i = 0; i < numwords; i++) { + if (((uint16_t *)start)[i] != INFOMEM_ERASED_WORD) { + return -3; + } + } - //init struct with standard values - sInfomem.startaddr = (uint16_t *) start; - sInfomem.size = 0; - sInfomem.maxsize = (end - start - 6) / 2; - sInfomem.not_lock = 0; + //init struct with standard values + sInfomem.startaddr = (uint16_t *) start; + sInfomem.size = 0; + sInfomem.maxsize = (end - start - 6) / 2; + sInfomem.not_lock = 0; - //prepare the three words of the initial structure - uint16_t buf[3] = {INFOMEM_IDENTIFIER, ((numwords - 3) & 0xFF) << 8, INFOMEM_TERMINATOR}; + //prepare the three words of the initial structure + uint16_t buf[3] = {INFOMEM_IDENTIFIER, ((numwords - 3) & 0xFF) << 8, INFOMEM_TERMINATOR}; - //write the initial structure to memory - infomem_write_data((uint16_t *)start, buf, 3); + //write the initial structure to memory + infomem_write_data((uint16_t *)start, buf, 3); - //make structure usable - sInfomem.sane = INFOMEM_SANE; - sInfomem.not_lock = 1; + //make structure usable + sInfomem.sane = INFOMEM_SANE; + sInfomem.not_lock = 1; - return sInfomem.maxsize; + return sInfomem.maxsize; }; @@ -412,15 +412,15 @@ int16_t infomem_init(uint16_t start, uint16_t end) // ************************************************************************************************* int16_t infomem_space() { - int16_t ret; + int16_t ret; - if (sInfomem.sane != INFOMEM_SANE) { - if ((ret = infomem_ready()) < 0) { - return ret; - } - } + if (sInfomem.sane != INFOMEM_SANE) { + if ((ret = infomem_ready()) < 0) { + return ret; + } + } - return sInfomem.maxsize - sInfomem.size; + return sInfomem.maxsize - sInfomem.size; } // ************************************************************************************************* @@ -437,64 +437,64 @@ int16_t infomem_space() // ************************************************************************************************* int16_t infomem_relocate(uint16_t start, uint16_t end) { - //check if we really have word addresses - if ((start & 0x1) || (end & 0x1)) { - return -3; - } - - if (sInfomem.sane != INFOMEM_SANE) { - return -1; - } - - //check if range is within memory - if (end > INFOMEM_START + 4 * INFOMEM_SEGMENT_SIZE || start < INFOMEM_START) { - return -4; - } - - //check if new memory range is big enough - if ((uint16_t *)end < (uint16_t *)start + sInfomem.size + 3) { - return -5; - } - - //try to avoid conflicts while writing - if (sInfomem.not_lock == 0) { - return -2; - } - - sInfomem.not_lock = 0; - - - uint16_t *old_end = sInfomem.startaddr + sInfomem.maxsize + 3; - - sInfomem.maxsize = (uint16_t *)end - (uint16_t *)start - 3; - - //new address of size word - uint16_t *mod_addr = (uint16_t *)start + 1; - - //prepare new size word - uint16_t buf; - ((uint8_t *)(&buf))[0] = sInfomem.size; - ((uint8_t *)(&buf))[1] = sInfomem.maxsize; - - //no relocation, just resize - if ((uint16_t *)start == sInfomem.startaddr) { - infomem_write_data(mod_addr, &buf, 1); - } - //left shift (might be with resize) - else if ((uint16_t *)start < sInfomem.startaddr) { - //delete bytes before information memory - infomem_insert_delete_modify((uint16_t *)start, NULL, (uint8_t)(sInfomem.startaddr - (uint16_t *)start), 0, &mod_addr, &buf, 1, sInfomem.startaddr + 3 + sInfomem.size, old_end); - } - //right shift - else { - //insert empty bytes before information memory - infomem_insert_delete_modify(sInfomem.startaddr, NULL, 0, (uint8_t)((uint16_t *)start - sInfomem.startaddr), &mod_addr, &buf, 1, sInfomem.startaddr + 3 + sInfomem.size, (uint16_t *)start + 3 + sInfomem.maxsize); - } - - sInfomem.startaddr = (uint16_t *)start; - - sInfomem.not_lock = 1; - return sInfomem.maxsize; + //check if we really have word addresses + if ((start & 0x1) || (end & 0x1)) { + return -3; + } + + if (sInfomem.sane != INFOMEM_SANE) { + return -1; + } + + //check if range is within memory + if (end > INFOMEM_START + 4 * INFOMEM_SEGMENT_SIZE || start < INFOMEM_START) { + return -4; + } + + //check if new memory range is big enough + if ((uint16_t *)end < (uint16_t *)start + sInfomem.size + 3) { + return -5; + } + + //try to avoid conflicts while writing + if (sInfomem.not_lock == 0) { + return -2; + } + + sInfomem.not_lock = 0; + + + uint16_t *old_end = sInfomem.startaddr + sInfomem.maxsize + 3; + + sInfomem.maxsize = (uint16_t *)end - (uint16_t *)start - 3; + + //new address of size word + uint16_t *mod_addr = (uint16_t *)start + 1; + + //prepare new size word + uint16_t buf; + ((uint8_t *)(&buf))[0] = sInfomem.size; + ((uint8_t *)(&buf))[1] = sInfomem.maxsize; + + //no relocation, just resize + if ((uint16_t *)start == sInfomem.startaddr) { + infomem_write_data(mod_addr, &buf, 1); + } + //left shift (might be with resize) + else if ((uint16_t *)start < sInfomem.startaddr) { + //delete bytes before information memory + infomem_insert_delete_modify((uint16_t *)start, NULL, (uint8_t)(sInfomem.startaddr - (uint16_t *)start), 0, &mod_addr, &buf, 1, sInfomem.startaddr + 3 + sInfomem.size, old_end); + } + //right shift + else { + //insert empty bytes before information memory + infomem_insert_delete_modify(sInfomem.startaddr, NULL, 0, (uint8_t)((uint16_t *)start - sInfomem.startaddr), &mod_addr, &buf, 1, sInfomem.startaddr + 3 + sInfomem.size, (uint16_t *)start + 3 + sInfomem.maxsize); + } + + sInfomem.startaddr = (uint16_t *)start; + + sInfomem.not_lock = 1; + return sInfomem.maxsize; } // ************************************************************************************************* @@ -506,18 +506,18 @@ int16_t infomem_relocate(uint16_t start, uint16_t end) // ************************************************************************************************* int16_t infomem_delete_all(void) { - if (sInfomem.sane != INFOMEM_SANE) { - return -1; - } - - //overwrite complete previously reserved memory with erased bytes - infomem_insert_delete_modify(sInfomem.startaddr, NULL, sInfomem.maxsize + 3, sInfomem.maxsize + 3, NULL, NULL, 0, sInfomem.startaddr + 3 + sInfomem.size, sInfomem.startaddr + 3 + sInfomem.maxsize); - - sInfomem.sane = 0; - sInfomem.startaddr = NULL; - sInfomem.size = 0; - sInfomem.maxsize = 0; - return 0; + if (sInfomem.sane != INFOMEM_SANE) { + return -1; + } + + //overwrite complete previously reserved memory with erased bytes + infomem_insert_delete_modify(sInfomem.startaddr, NULL, sInfomem.maxsize + 3, sInfomem.maxsize + 3, NULL, NULL, 0, sInfomem.startaddr + 3 + sInfomem.size, sInfomem.startaddr + 3 + sInfomem.maxsize); + + sInfomem.sane = 0; + sInfomem.startaddr = NULL; + sInfomem.size = 0; + sInfomem.maxsize = 0; + return 0; } // ************************************************************************************************* @@ -530,17 +530,17 @@ int16_t infomem_delete_all(void) // ************************************************************************************************* int16_t infomem_app_amount(uint8_t identifier) { - if (sInfomem.sane != INFOMEM_SANE) { - return -1; - } + if (sInfomem.sane != INFOMEM_SANE) { + return -1; + } - uint16_t *addr = infomem_get_app_addr(identifier); + uint16_t *addr = infomem_get_app_addr(identifier); - if (addr == NULL) { - return 0; - } + if (addr == NULL) { + return 0; + } - return ((uint8_t *)addr)[1]; + return ((uint8_t *)addr)[1]; } @@ -558,41 +558,41 @@ int16_t infomem_app_amount(uint8_t identifier) // ************************************************************************************************* int16_t infomem_app_read(uint8_t identifier, uint16_t *data, uint8_t count, uint8_t offset) { - if (sInfomem.sane != INFOMEM_SANE) { - return -1; - } + if (sInfomem.sane != INFOMEM_SANE) { + return -1; + } - //find application - uint16_t *addr = infomem_get_app_addr(identifier); + //find application + uint16_t *addr = infomem_get_app_addr(identifier); - if (addr == NULL) { - return 0; - } + if (addr == NULL) { + return 0; + } - //read application size - uint8_t size = ((uint8_t *)addr)[1]; + //read application size + uint8_t size = ((uint8_t *)addr)[1]; - //check if offset is still within application memory - if (offset >= size) { - return 0; - } + //check if offset is still within application memory + if (offset >= size) { + return 0; + } - //do not read more data than what is present - if (count + offset > size) { - count = size - offset; - } + //do not read more data than what is present + if (count + offset > size) { + count = size - offset; + } - //set address to read from - addr += offset + 1; + //set address to read from + addr += offset + 1; - int i; + int i; - //copy data - for (i = 0; i < count; i++) { - data[i] = addr[i]; - } + //copy data + for (i = 0; i < count; i++) { + data[i] = addr[i]; + } - return count; + return count; } // ************************************************************************************************* @@ -608,73 +608,73 @@ int16_t infomem_app_read(uint8_t identifier, uint16_t *data, uint8_t count, uint // ************************************************************************************************* int16_t infomem_app_replace(uint8_t identifier, uint16_t *data, uint8_t count) { - //delete app completely if we have to replace it with zero content. - if (count == 0) { - return infomem_app_delete(identifier, 0); - } - - if (sInfomem.sane != INFOMEM_SANE) { - return -1; - } - - if (sInfomem.not_lock == 0) { - return -2; - } - - sInfomem.not_lock = 0; - - uint8_t old_size = 0; - //get address of application - uint16_t *addr = infomem_get_app_addr(identifier); - - //application is already present, really replace memory content - if (addr != NULL) { - old_size = ((uint8_t *)addr)[1]; - - //check if new data does fit - if ((int16_t)sInfomem.size + (int16_t) count - (int16_t)old_size > sInfomem.maxsize) { - sInfomem.not_lock = 1; - return -4; - } - - //set global header and application header to be modified - uint16_t *mod_addr[2] = {sInfomem.startaddr + 1, addr}; - uint16_t mod_data[2]; - ((uint8_t *)mod_data)[0] = sInfomem.size + count - old_size; - ((uint8_t *)mod_data)[1] = sInfomem.maxsize; - ((uint8_t *)mod_data)[2] = identifier; - ((uint8_t *)mod_data)[3] = count; - - //delete old_size words and write count new words instead, also replace headers - infomem_insert_delete_modify(addr + 1, data, old_size, count, mod_addr, mod_data, 2, sInfomem.startaddr + 3 + sInfomem.size, sInfomem.startaddr + 3 + sInfomem.maxsize); - //store new size - sInfomem.size = ((uint8_t *)mod_data)[0]; - } - //application not present, add it at the end of the information memory - else { - //check if new data does fit - if ((int16_t)sInfomem.size + (int16_t) count + 1 > sInfomem.maxsize) { - sInfomem.not_lock = 1; - return -4; - } - - //prepare header words - uint16_t *mod_addr[2] = {sInfomem.startaddr + 1, sInfomem.startaddr + 2 + sInfomem.size}; - uint16_t mod_data[2]; - ((uint8_t *)mod_data)[0] = sInfomem.size + count + 1; - ((uint8_t *)mod_data)[1] = sInfomem.maxsize; - ((uint8_t *)mod_data)[2] = identifier; - ((uint8_t *)mod_data)[3] = count; - - //hack: to write the application header and size add it to mod, increase count and decrease data pointer. the first data word at data-1 will not be read - //this avoids copying data to add a header - infomem_insert_delete_modify(sInfomem.startaddr + 2 + sInfomem.size, data - 1, 0, count + 1, mod_addr, mod_data, 2, sInfomem.startaddr + 3 + sInfomem.size, sInfomem.startaddr + 3 + sInfomem.maxsize); - //store size - sInfomem.size = ((uint8_t *)mod_data)[0]; - } - - sInfomem.not_lock = 1; - return sInfomem.size; + //delete app completely if we have to replace it with zero content. + if (count == 0) { + return infomem_app_delete(identifier, 0); + } + + if (sInfomem.sane != INFOMEM_SANE) { + return -1; + } + + if (sInfomem.not_lock == 0) { + return -2; + } + + sInfomem.not_lock = 0; + + uint8_t old_size = 0; + //get address of application + uint16_t *addr = infomem_get_app_addr(identifier); + + //application is already present, really replace memory content + if (addr != NULL) { + old_size = ((uint8_t *)addr)[1]; + + //check if new data does fit + if ((int16_t)sInfomem.size + (int16_t) count - (int16_t)old_size > sInfomem.maxsize) { + sInfomem.not_lock = 1; + return -4; + } + + //set global header and application header to be modified + uint16_t *mod_addr[2] = {sInfomem.startaddr + 1, addr}; + uint16_t mod_data[2]; + ((uint8_t *)mod_data)[0] = sInfomem.size + count - old_size; + ((uint8_t *)mod_data)[1] = sInfomem.maxsize; + ((uint8_t *)mod_data)[2] = identifier; + ((uint8_t *)mod_data)[3] = count; + + //delete old_size words and write count new words instead, also replace headers + infomem_insert_delete_modify(addr + 1, data, old_size, count, mod_addr, mod_data, 2, sInfomem.startaddr + 3 + sInfomem.size, sInfomem.startaddr + 3 + sInfomem.maxsize); + //store new size + sInfomem.size = ((uint8_t *)mod_data)[0]; + } + //application not present, add it at the end of the information memory + else { + //check if new data does fit + if ((int16_t)sInfomem.size + (int16_t) count + 1 > sInfomem.maxsize) { + sInfomem.not_lock = 1; + return -4; + } + + //prepare header words + uint16_t *mod_addr[2] = {sInfomem.startaddr + 1, sInfomem.startaddr + 2 + sInfomem.size}; + uint16_t mod_data[2]; + ((uint8_t *)mod_data)[0] = sInfomem.size + count + 1; + ((uint8_t *)mod_data)[1] = sInfomem.maxsize; + ((uint8_t *)mod_data)[2] = identifier; + ((uint8_t *)mod_data)[3] = count; + + //hack: to write the application header and size add it to mod, increase count and decrease data pointer. the first data word at data-1 will not be read + //this avoids copying data to add a header + infomem_insert_delete_modify(sInfomem.startaddr + 2 + sInfomem.size, data - 1, 0, count + 1, mod_addr, mod_data, 2, sInfomem.startaddr + 3 + sInfomem.size, sInfomem.startaddr + 3 + sInfomem.maxsize); + //store size + sInfomem.size = ((uint8_t *)mod_data)[0]; + } + + sInfomem.not_lock = 1; + return sInfomem.size; } // ************************************************************************************************* @@ -688,7 +688,7 @@ int16_t infomem_app_replace(uint8_t identifier, uint16_t *data, uint8_t count) // ************************************************************************************************* int16_t infomem_app_clear(uint8_t identifier) { - return infomem_app_delete(identifier, 0); + return infomem_app_delete(identifier, 0); } // ************************************************************************************************* @@ -705,65 +705,65 @@ int16_t infomem_app_clear(uint8_t identifier) // ************************************************************************************************* int16_t infomem_app_delete(uint8_t identifier, uint8_t offset) { - if (sInfomem.sane != INFOMEM_SANE) { - return -1; - } - - if (sInfomem.not_lock == 0) { - return -2; - } - - sInfomem.not_lock = 0; - - //get address of application - uint16_t *addr = infomem_get_app_addr(identifier); - - if (addr == NULL) { - sInfomem.not_lock = 1; - return 0; - } - - //get old size of application - uint8_t old_size = ((uint8_t *)addr)[1]; - - //delete application completely - if (offset == 0) { - //prepare global size header - uint16_t *mod_addr[1] = {sInfomem.startaddr + 1}; - uint16_t mod_data[1]; - ((uint8_t *)mod_data)[0] = sInfomem.size - old_size - 1; - ((uint8_t *)mod_data)[1] = sInfomem.maxsize; - - infomem_insert_delete_modify(addr, NULL, old_size + 1, 0, mod_addr, mod_data, 1, sInfomem.startaddr + 3 + sInfomem.size, sInfomem.startaddr + 3 + sInfomem.maxsize); - //store new size - sInfomem.size = ((uint8_t *)mod_data)[0]; - } - //let some data be present - else { - //check if offset is in range - if (offset >= old_size) { - sInfomem.not_lock = 1; - return -3; - } - - //determine count of data to be deleted - uint8_t count_delete = old_size - offset; - - //prepare new size headers - uint16_t *mod_addr[2] = {sInfomem.startaddr + 1, addr}; - uint16_t mod_data[2]; - ((uint8_t *)mod_data)[0] = sInfomem.size - count_delete; - ((uint8_t *)mod_data)[1] = sInfomem.maxsize; - ((uint8_t *)mod_data)[2] = identifier; - ((uint8_t *)mod_data)[3] = old_size - count_delete; - - infomem_insert_delete_modify(addr + 1 + offset, NULL, count_delete, 0, mod_addr, mod_data, 2, sInfomem.startaddr + 3 + sInfomem.size, sInfomem.startaddr + 3 + sInfomem.maxsize); - //store new size - sInfomem.size = ((uint8_t *)mod_data)[0]; - } - - sInfomem.not_lock = 1; - return sInfomem.size; + if (sInfomem.sane != INFOMEM_SANE) { + return -1; + } + + if (sInfomem.not_lock == 0) { + return -2; + } + + sInfomem.not_lock = 0; + + //get address of application + uint16_t *addr = infomem_get_app_addr(identifier); + + if (addr == NULL) { + sInfomem.not_lock = 1; + return 0; + } + + //get old size of application + uint8_t old_size = ((uint8_t *)addr)[1]; + + //delete application completely + if (offset == 0) { + //prepare global size header + uint16_t *mod_addr[1] = {sInfomem.startaddr + 1}; + uint16_t mod_data[1]; + ((uint8_t *)mod_data)[0] = sInfomem.size - old_size - 1; + ((uint8_t *)mod_data)[1] = sInfomem.maxsize; + + infomem_insert_delete_modify(addr, NULL, old_size + 1, 0, mod_addr, mod_data, 1, sInfomem.startaddr + 3 + sInfomem.size, sInfomem.startaddr + 3 + sInfomem.maxsize); + //store new size + sInfomem.size = ((uint8_t *)mod_data)[0]; + } + //let some data be present + else { + //check if offset is in range + if (offset >= old_size) { + sInfomem.not_lock = 1; + return -3; + } + + //determine count of data to be deleted + uint8_t count_delete = old_size - offset; + + //prepare new size headers + uint16_t *mod_addr[2] = {sInfomem.startaddr + 1, addr}; + uint16_t mod_data[2]; + ((uint8_t *)mod_data)[0] = sInfomem.size - count_delete; + ((uint8_t *)mod_data)[1] = sInfomem.maxsize; + ((uint8_t *)mod_data)[2] = identifier; + ((uint8_t *)mod_data)[3] = old_size - count_delete; + + infomem_insert_delete_modify(addr + 1 + offset, NULL, count_delete, 0, mod_addr, mod_data, 2, sInfomem.startaddr + 3 + sInfomem.size, sInfomem.startaddr + 3 + sInfomem.maxsize); + //store new size + sInfomem.size = ((uint8_t *)mod_data)[0]; + } + + sInfomem.not_lock = 1; + return sInfomem.size; } // ************************************************************************************************* @@ -783,63 +783,63 @@ int16_t infomem_app_delete(uint8_t identifier, uint8_t offset) // ************************************************************************************************* int16_t infomem_app_modify(uint8_t identifier, uint16_t *data, uint8_t count, uint8_t offset) { - if (sInfomem.sane != INFOMEM_SANE) { - return -1; - } - - if (sInfomem.not_lock == 0) { - return -2; - } - - sInfomem.not_lock = 0; - - uint16_t *addr = infomem_get_app_addr(identifier); - - if (addr == NULL) { - sInfomem.not_lock = 1; - return 0; - } - - uint8_t old_size = ((uint8_t *)addr)[1]; - - if (offset > old_size) { - sInfomem.not_lock = 1; - return -3; - } - - //new data does fit in old data, just modify the selected words - if (count + offset <= old_size) { - infomem_write_data(addr + 1 + offset, data, count); - sInfomem.not_lock = 1; - return old_size; - } - //new data does not fit, increase size of application's storage - else { - //calculate number of words that are overwritten - uint8_t count_delete = old_size - offset; - - //check if new data does fit into memory - if ((int16_t)sInfomem.size - (int16_t)count_delete + (int16_t) count > sInfomem.maxsize) { - sInfomem.not_lock = 1; - return -4; - } - - //prepare new headers with size - uint16_t *mod_addr[2] = {sInfomem.startaddr + 1, addr}; - uint16_t mod_data[2]; - ((uint8_t *)mod_data)[0] = sInfomem.size - count_delete + count; - ((uint8_t *)mod_data)[1] = sInfomem.maxsize; - ((uint8_t *)mod_data)[2] = identifier; - ((uint8_t *)mod_data)[3] = old_size - count_delete + count; - - infomem_insert_delete_modify(addr + 1 + offset, data, count_delete, count, mod_addr, mod_data, 2, sInfomem.startaddr + 3 + sInfomem.size, sInfomem.startaddr + 3 + sInfomem.maxsize); - - //store new size - sInfomem.size = ((uint8_t *)mod_data)[0]; - - sInfomem.not_lock = 1; - return offset + count; - } + if (sInfomem.sane != INFOMEM_SANE) { + return -1; + } + + if (sInfomem.not_lock == 0) { + return -2; + } + + sInfomem.not_lock = 0; + + uint16_t *addr = infomem_get_app_addr(identifier); + + if (addr == NULL) { + sInfomem.not_lock = 1; + return 0; + } + + uint8_t old_size = ((uint8_t *)addr)[1]; + + if (offset > old_size) { + sInfomem.not_lock = 1; + return -3; + } + + //new data does fit in old data, just modify the selected words + if (count + offset <= old_size) { + infomem_write_data(addr + 1 + offset, data, count); + sInfomem.not_lock = 1; + return old_size; + } + //new data does not fit, increase size of application's storage + else { + //calculate number of words that are overwritten + uint8_t count_delete = old_size - offset; + + //check if new data does fit into memory + if ((int16_t)sInfomem.size - (int16_t)count_delete + (int16_t) count > sInfomem.maxsize) { + sInfomem.not_lock = 1; + return -4; + } + + //prepare new headers with size + uint16_t *mod_addr[2] = {sInfomem.startaddr + 1, addr}; + uint16_t mod_data[2]; + ((uint8_t *)mod_data)[0] = sInfomem.size - count_delete + count; + ((uint8_t *)mod_data)[1] = sInfomem.maxsize; + ((uint8_t *)mod_data)[2] = identifier; + ((uint8_t *)mod_data)[3] = old_size - count_delete + count; + + infomem_insert_delete_modify(addr + 1 + offset, data, count_delete, count, mod_addr, mod_data, 2, sInfomem.startaddr + 3 + sInfomem.size, sInfomem.startaddr + 3 + sInfomem.maxsize); + + //store new size + sInfomem.size = ((uint8_t *)mod_data)[0]; + + sInfomem.not_lock = 1; + return offset + count; + } } #endif diff --git a/drivers/infomem.h b/drivers/infomem.h index 7a74a36..e11b489 100644 --- a/drivers/infomem.h +++ b/drivers/infomem.h @@ -58,11 +58,11 @@ extern int16_t infomem_app_modify(uint8_t identifier, uint16_t *data, uint8_t co struct infomem { - uint16_t *startaddr; //starting address (position of header) - uint8_t size; //size of payload in words - uint8_t maxsize; //maximum size of payload in words - volatile uint8_t not_lock; //memory is not locked for write - uint8_t sane; //sanity check passed + uint16_t *startaddr; //starting address (position of header) + uint8_t size; //size of payload in words + uint8_t maxsize; //maximum size of payload in words + volatile uint8_t not_lock; //memory is not locked for write + uint8_t sane; //sanity check passed }; // extern struct infomem sInfomem; @@ -81,4 +81,4 @@ struct infomem { #define INFOMEM_ERASED_WORD 0xFFFF -#endif /*INFOMEM_H_*/ \ No newline at end of file +#endif /*INFOMEM_H_*/ diff --git a/drivers/lpm.c b/drivers/lpm.c index 2101a87..849ee94 100644 --- a/drivers/lpm.c +++ b/drivers/lpm.c @@ -1,36 +1,36 @@ /** - drivers/lpm.h: Low power mode driver + drivers/lpm.h: Low power mode driver - Copyright (C) 2017 Benjamin Sølberg + Copyright (C) 2017 Benjamin Sølberg - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ #include "lpm.h" #include "buzzer.h" void enter_lpm_gie(uint16_t LPM_bits) { - if (is_buzzer_playing()) { - // Override LPM bits to LPM0 because we need SMCLK for tone generation as well as FLL for stability - LPM_bits = LPM0_bits; - } - - /* Go to LPMx & wait for interrupts */ - _BIS_SR(LPM_bits | GIE); - __no_operation(); + if (is_buzzer_playing()) { + // Override LPM bits to LPM0 because we need SMCLK for tone generation as well as FLL for stability + LPM_bits = LPM0_bits; + } + + /* Go to LPMx & wait for interrupts */ + _BIS_SR(LPM_bits | GIE); + __no_operation(); } diff --git a/drivers/lpm.h b/drivers/lpm.h index 51475aa..28c8ea9 100644 --- a/drivers/lpm.h +++ b/drivers/lpm.h @@ -1,24 +1,24 @@ /** - drivers/lpm.h: Low power mode driver + drivers/lpm.h: Low power mode driver - Copyright (C) 2017 Benjamin Sølberg + Copyright (C) 2017 Benjamin Sølberg - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ #ifndef LPM_H_ diff --git a/drivers/pmm.c b/drivers/pmm.c index e334471..cc98cf7 100644 --- a/drivers/pmm.c +++ b/drivers/pmm.c @@ -19,17 +19,17 @@ //****************************************************************************// void SetVCore(unsigned char level) // Note: change level by one step only { - unsigned char actLevel; + unsigned char actLevel; - do { - actLevel = PMMCTL0_L & PMMCOREV_3; + do { + actLevel = PMMCTL0_L & PMMCOREV_3; - if (actLevel < level) - SetVCoreUp(++actLevel); // Set VCore (step by step) + if (actLevel < level) + SetVCoreUp(++actLevel); // Set VCore (step by step) - if (actLevel > level) - SetVCoreDown(--actLevel); // Set VCore (step by step) - } while (actLevel != level); + if (actLevel > level) + SetVCoreDown(--actLevel); // Set VCore (step by step) + } while (actLevel != level); } @@ -38,22 +38,22 @@ void SetVCore(unsigned char level) // Note: change level by one step onl //****************************************************************************// void SetVCoreUp(unsigned char level) // Note: change level by one step only { - PMMCTL0_H = 0xA5; // Open PMM module registers for write access + PMMCTL0_H = 0xA5; // Open PMM module registers for write access - SVSMHCTL = SVSHE + SVSHRVL0 * level + SVMHE + SVSMHRRL0 * level; // Set SVS/M high side to new level + SVSMHCTL = SVSHE + SVSHRVL0 * level + SVMHE + SVSMHRRL0 * level; // Set SVS/M high side to new level - SVSMLCTL = SVSLE + SVMLE + SVSMLRRL0 * level; // Set SVM new Level + SVSMLCTL = SVSLE + SVMLE + SVSMLRRL0 * level; // Set SVM new Level - while ((PMMIFG & SVSMLDLYIFG) == 0); // Wait till SVM is settled (Delay) + while ((PMMIFG & SVSMLDLYIFG) == 0); // Wait till SVM is settled (Delay) - PMMCTL0_L = PMMCOREV0 * level; // Set VCore to x - PMMIFG &= ~(SVMLVLRIFG + SVMLIFG); // Clear already set flags + PMMCTL0_L = PMMCOREV0 * level; // Set VCore to x + PMMIFG &= ~(SVMLVLRIFG + SVMLIFG); // Clear already set flags - if ((PMMIFG & SVMLIFG)) - while ((PMMIFG & SVMLVLRIFG) == 0); // Wait till level is reached + if ((PMMIFG & SVMLIFG)) + while ((PMMIFG & SVMLVLRIFG) == 0); // Wait till level is reached - SVSMLCTL = SVSLE + SVSLRVL0 * level + SVMLE + SVSMLRRL0 * level; // Set SVS/M Low side to new level - PMMCTL0_H = 0x00; // Lock PMM module registers for write access + SVSMLCTL = SVSLE + SVSLRVL0 * level + SVMLE + SVSMLRRL0 * level; // Set SVS/M Low side to new level + PMMCTL0_H = 0x00; // Lock PMM module registers for write access } @@ -63,13 +63,13 @@ void SetVCoreUp(unsigned char level) // Note: change level by one step o //****************************************************************************// void SetVCoreDown(unsigned char level) { - PMMCTL0_H = 0xA5; // Open PMM module registers for write access - SVSMLCTL = SVSLE + SVSLRVL0 * level + SVMLE + SVSMLRRL0 * level; // Set SVS/M Low side to new level + PMMCTL0_H = 0xA5; // Open PMM module registers for write access + SVSMLCTL = SVSLE + SVSLRVL0 * level + SVMLE + SVSMLRRL0 * level; // Set SVS/M Low side to new level - while ((PMMIFG & SVSMLDLYIFG) == 0); // Wait till SVM is settled (Delay) + while ((PMMIFG & SVSMLDLYIFG) == 0); // Wait till SVM is settled (Delay) - PMMCTL0_L = (level * PMMCOREV0); // Set VCore to 1.85 V for Max Speed. - PMMCTL0_H = 0x00; // Lock PMM module registers for write access + PMMCTL0_L = (level * PMMCOREV0); // Set VCore to 1.85 V for Max Speed. + PMMCTL0_H = 0x00; // Lock PMM module registers for write access } diff --git a/drivers/pmm.h b/drivers/pmm.h index a6acb60..1dca44f 100644 --- a/drivers/pmm.h +++ b/drivers/pmm.h @@ -17,26 +17,26 @@ //==================================================================== /** - * Set the VCore to a new level - * - * \param level PMM level ID - */ + * Set the VCore to a new level + * + * \param level PMM level ID + */ void SetVCore(unsigned char level); //==================================================================== /** - * Set the VCore to a new higher level - * - * \param level PMM level ID - */ + * Set the VCore to a new higher level + * + * \param level PMM level ID + */ void SetVCoreUp(unsigned char level); //==================================================================== /** - * Set the VCore to a new Lower level - * - * \param level PMM level ID - */ + * Set the VCore to a new Lower level + * + * \param level PMM level ID + */ void SetVCoreDown(unsigned char level); #endif /* __PMM */ diff --git a/drivers/ports.c b/drivers/ports.c index 1b33ac2..c0d0642 100644 --- a/drivers/ports.c +++ b/drivers/ports.c @@ -1,26 +1,26 @@ /** - drivers/ports.c: Openchronos ports driver + drivers/ports.c: Openchronos ports driver - Copyright (C) 2012 Angelo Arrifano - Copyright (C) 2013 Martin AusChemnitz - Copyright (C) 2016-2017 Benjamin Sølberg + Copyright (C) 2012 Angelo Arrifano + Copyright (C) 2013 Martin AusChemnitz + Copyright (C) 2016-2017 Benjamin Sølberg - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ #include "openchronos.h" @@ -30,9 +30,8 @@ #include "timer.h" #include "utils.h" -#ifdef CONFIG_MOD_ACCELEROMETER -#include "vti_as.h" -#endif +#include "as.h" +#include "ps.h" #define ALL_BUTTONS 0x1F @@ -53,69 +52,69 @@ static uint8_t silent_until_release = 0xff; */ static void callback_20Hz() { - static uint8_t last_state; - uint8_t buttons = P2IN & ALL_BUTTONS; - - ports_down_btns |= ((last_state ^ buttons) & buttons) & silent_until_release; - /* (buttons that changed) */ - uint8_t released = ((last_state ^ buttons) & ~buttons) & silent_until_release; - silent_until_release |= ~buttons; - last_state = buttons; - - uint16_t pressed_ticks = timer0_20hz_counter - last_press; - /* check how long btn was pressed and save the event */ - if (pressed_ticks > CONFIG_BUTTONS_LONG_PRESS_TIME) { - /* suppress */ - silent_until_release &= ~buttons; - ports_pressed_btns |= buttons << 5; - } else { - ports_pressed_btns |= released; - } - - if (!buttons) { - /* turn 20 Hz timer off */ - stop_timer0_20hz(); - timer_20Hz_started = 0; - } + static uint8_t last_state; + uint8_t buttons = P2IN & ALL_BUTTONS; + + ports_down_btns |= ((last_state ^ buttons) & buttons) & silent_until_release; + /* (buttons that changed) */ + uint8_t released = ((last_state ^ buttons) & ~buttons) & silent_until_release; + silent_until_release |= ~buttons; + last_state = buttons; + + uint16_t pressed_ticks = timer0_20hz_counter - last_press; + /* check how long btn was pressed and save the event */ + if (pressed_ticks > CONFIG_BUTTONS_LONG_PRESS_TIME) { + /* suppress */ + silent_until_release &= ~buttons; + ports_pressed_btns |= buttons << 5; + } else { + ports_pressed_btns |= released; + } + + if (!buttons) { + /* turn 20 Hz timer off */ + stop_timer0_20hz(); + timer_20Hz_started = 0; + } } void init_buttons(void) { - /* Set button ports to input */ - P2DIR &= ~ALL_BUTTONS; + /* Set button ports to input */ + P2DIR &= ~ALL_BUTTONS; - /* Enable internal pull-downs */ - P2OUT &= ~ALL_BUTTONS; - P2REN |= ALL_BUTTONS; + /* Enable internal pull-downs */ + P2OUT &= ~ALL_BUTTONS; + P2REN |= ALL_BUTTONS; - /* IRQ triggers on rising edge */ - P2IES &= ~ALL_BUTTONS; + /* IRQ triggers on rising edge */ + P2IES &= ~ALL_BUTTONS; - /* Reset IRQ flags */ - P2IFG &= ~ALL_BUTTONS; + /* Reset IRQ flags */ + P2IFG &= ~ALL_BUTTONS; - /* Enable button interrupts */ - P2IE |= ALL_BUTTONS; + /* Enable button interrupts */ + P2IE |= ALL_BUTTONS; } bool is_ports_button_pressed() { - return ports_down_btns != 0; + return ports_down_btns != 0; } static uint8_t _ports_button_pressed(uint8_t btn, uint8_t with_longpress, uint8_t peek) { - if (with_longpress) { - return BIT_IS_SET(ports_pressed_btns, btn); - } else { - if (BIT_IS_SET(ports_down_btns, btn)) { - /* suppress */ - if (!peek) - silent_until_release &= ~btn; - return 1; - } else { - return 0; - } - } + if (with_longpress) { + return BIT_IS_SET(ports_pressed_btns, btn); + } else { + if (BIT_IS_SET(ports_down_btns, btn)) { + /* suppress */ + if (!peek) + silent_until_release &= ~btn; + return 1; + } else { + return 0; + } + } } /* @@ -123,7 +122,7 @@ static uint8_t _ports_button_pressed(uint8_t btn, uint8_t with_longpress, uint8_ */ uint8_t ports_button_pressed(uint8_t btn, uint8_t with_longpress) { - return _ports_button_pressed(btn, with_longpress, 0); + return _ports_button_pressed(btn, with_longpress, 0); } /* @@ -131,7 +130,7 @@ uint8_t ports_button_pressed(uint8_t btn, uint8_t with_longpress) */ uint8_t ports_button_pressed_peek(uint8_t btn, uint8_t with_longpress) { - return _ports_button_pressed(btn, with_longpress, 1); + return _ports_button_pressed(btn, with_longpress, 1); } /* @@ -139,8 +138,8 @@ uint8_t ports_button_pressed_peek(uint8_t btn, uint8_t with_longpress) */ void ports_buttons_clear(void) { - ports_down_btns = 0; - ports_pressed_btns = 0; + ports_down_btns = 0; + ports_pressed_btns = 0; } /* @@ -149,39 +148,40 @@ void ports_buttons_clear(void) */ void ports_buttons_poll(void) { - if (timer0_last_event | TIMER0_EVENT_20HZ && timer_20Hz_started) - callback_20Hz(); + if (timer0_last_event | TIMER0_EVENT_20HZ && timer_20Hz_started) + callback_20Hz(); } /* Interrupt service routine for - - buttons - - acceleration sensor CMA_INT - - pressure sensor DRDY + - buttons + - acceleration sensor CMA_INT + - pressure sensor DRDY */ __attribute__((interrupt(PORT2_VECTOR))) void PORT2_ISR(void) { - /* If the interrupt is a button press */ - if (P2IFG & ALL_BUTTONS) { - /* turn on 20 Hz callback*/ - if (!timer_20Hz_started) { - last_press = timer0_20hz_counter; - timer_20Hz_started = 1; - start_timer0_20hz(); - } - } - - /* Handle accelerometer */ - #ifdef CONFIG_MOD_ACCELEROMETER - /* Check if accelerometer interrupt flag */ - if ((P2IFG & AS_INT_PIN) == AS_INT_PIN) - as_last_interrupt = 1; - #endif - - /* A write to the interrupt vector, automatically clears the - latest interrupt */ - P2IV = 0x00; + /* If the interrupt is a button press */ + if (P2IFG & ALL_BUTTONS) { + /* turn on 20 Hz callback*/ + if (!timer_20Hz_started) { + last_press = timer0_20hz_counter; + timer_20Hz_started = 1; + start_timer0_20hz(); + } + } + + /* Handle accelerometer */ + /* Check if accelerometer interrupt flag */ + if ((P2IFG & AS_INT_PIN) == AS_INT_PIN) + as_last_interrupt = 1; + + if ((P2IFG & PS_INT_PIN) == PS_INT_PIN) + ps_last_interrupt = 1; + + /* A write to the interrupt vector, automatically clears the + latest interrupt */ + P2IV = 0x00; } diff --git a/drivers/ports.h b/drivers/ports.h index d736284..0943ad3 100644 --- a/drivers/ports.h +++ b/drivers/ports.h @@ -1,59 +1,59 @@ /** - drivers/ports.c: Openchronos ports driver + drivers/ports.c: Openchronos ports driver - Copyright (C) 2012 Angelo Arrifano - Copyright (C) 2013 Martin AusChemnitz - Copyright (C) 2016-2017 Benjamin Sølberg + Copyright (C) 2012 Angelo Arrifano + Copyright (C) 2013 Martin AusChemnitz + Copyright (C) 2016-2017 Benjamin Sølberg - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ /* - Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ - - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the - distribution. - - Neither the name of Texas Instruments Incorporated nor the names of - its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ + + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the + distribution. + + Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __PORTS_H__ @@ -71,20 +71,20 @@ enum ports_buttons { #ifdef CONFIG_BUTTONS_SWAP_UP_AND_DOWN - PORTS_BTN_DOWN = PORTS_BTN_UP_PIN, - PORTS_BTN_UP = PORTS_BTN_DOWN_PIN, + PORTS_BTN_DOWN = PORTS_BTN_UP_PIN, + PORTS_BTN_UP = PORTS_BTN_DOWN_PIN, #else - PORTS_BTN_DOWN = PORTS_BTN_DOWN_PIN, - PORTS_BTN_UP = PORTS_BTN_UP_PIN, + PORTS_BTN_DOWN = PORTS_BTN_DOWN_PIN, + PORTS_BTN_UP = PORTS_BTN_UP_PIN, #endif - PORTS_BTN_NUM = PORTS_BTN_NUM_PIN, - PORTS_BTN_STAR = PORTS_BTN_STAR_PIN, - PORTS_BTN_BL = PORTS_BTN_BL_PIN, - PORTS_BTN_LDOWN = BIT5, - PORTS_BTN_LNUM = BIT6, - PORTS_BTN_LSTAR = BIT7, - PORTS_BTN_LBL = BIT8, - PORTS_BTN_LUP = BIT9, + PORTS_BTN_NUM = PORTS_BTN_NUM_PIN, + PORTS_BTN_STAR = PORTS_BTN_STAR_PIN, + PORTS_BTN_BL = PORTS_BTN_BL_PIN, + PORTS_BTN_LDOWN = BIT5, + PORTS_BTN_LNUM = BIT6, + PORTS_BTN_LSTAR = BIT7, + PORTS_BTN_LBL = BIT8, + PORTS_BTN_LUP = BIT9, }; /* Global keypress peek, should normally NOT use be used, unless a global hook is needed */ diff --git a/drivers/ps.c b/drivers/ps.c new file mode 100644 index 0000000..6d3f4b3 --- /dev/null +++ b/drivers/ps.c @@ -0,0 +1,446 @@ +// ************************************************************************************************* +// +// Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the +// distribution. +// +// Neither the name of Texas Instruments Incorporated nor the names of +// its contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ************************************************************************************************* +// pressure sensor driver functions +// ************************************************************************************************* + +// ************************************************************************************************* +// Include section + +// system +#include "openchronos.h" + +// driver +#include "ps.h" +#include "timer.h" + +// ************************************************************************************************* +// Prototypes section + +// ************************************************************************************************* +// Defines section + +// ************************************************************************************************* +// Global Variable section + +// pressure (hPa) to altitude (m) conversion tables +const int16_t h0[17] = +{ -153, 0, 111, 540, 989, 1457, 1949, 2466, 3012, 3591, 4206, 4865, 5574, 6344, 7185, 8117, 9164 }; +const uint16_t p0[17] = +{ 1031, 1013, 1000, 950, 900, 850, 800, 750, 700, 650, 600, 550, 500, 450, 400, 350, 300 }; + +float p[17]; + +// ************************************************************************************************* +// Extern section + +// ************************************************************************************************* +// @fn bmp_ps_init +// @brief Init pressure sensor I/O +// @param none +// @return none +// ************************************************************************************************* +void ps_init(void) +{ + PS_INT_DIR &= ~PS_INT_PIN; // EOC is input + PS_INT_IES &= ~PS_INT_PIN; // Interrupt on EOC rising edge + PS_I2C_OUT |= PS_SCL_PIN + PS_SDA_PIN; // SCL and SDA are high by default + PS_I2C_DIR |= PS_SCL_PIN + PS_SDA_PIN; // SCL and SDA are outputs by default + + // 100msec delay to guarantee stable operation + timer0_delay(10, LPM3_bits); +} + +// ************************************************************************************************* +// @fn ps_i2c_sda +// @brief Control SDA line +// @param uint8_t condition PS_I2C_SEND_START, PS_I2C_SEND_RESTART, PS_I2C_SEND_STOP +// PS_I2C_CHECK_ACK +// @return uint8_t 1=ACK, 0=NACK +// ************************************************************************************************* +uint8_t ps_i2c_sda(uint8_t condition) +{ + uint8_t sda = 0; + + if (condition == PS_I2C_SEND_START) + { + PS_I2C_SDA_OUT; // SDA is output + PS_I2C_SCL_HI; + ps_i2c_delay(); + PS_I2C_SDA_LO; + ps_i2c_delay(); + PS_I2C_SCL_LO; // SDA 1-0 transition while SCL=1 (will be 0) + ps_i2c_delay(); + } + else if (condition == PS_I2C_SEND_RESTART) + { + PS_I2C_SDA_OUT; // SDA is output + PS_I2C_SCL_LO; + PS_I2C_SDA_HI; + ps_i2c_delay(); + PS_I2C_SCL_HI; + ps_i2c_delay(); + PS_I2C_SDA_LO; + ps_i2c_delay(); + PS_I2C_SCL_LO; // SDA 1-0 while SCL = 1 (was 0) + ps_i2c_delay(); + } + else if (condition == PS_I2C_SEND_STOP) + { + PS_I2C_SDA_OUT; // SDA is output + PS_I2C_SDA_LO; + ps_i2c_delay(); + PS_I2C_SCL_LO; + ps_i2c_delay(); + PS_I2C_SCL_HI; + ps_i2c_delay(); + PS_I2C_SDA_HI; // SDA 0-1 transition while SCL=1 + ps_i2c_delay(); + } + else if (condition == PS_I2C_CHECK_ACK) + { + PS_I2C_SDA_IN; // SDA is input + PS_I2C_SCL_LO; + ps_i2c_delay(); + PS_I2C_SCL_HI; + ps_i2c_delay(); + sda = PS_I2C_IN & PS_SDA_PIN; // ACK = SDA during ack clock pulse + PS_I2C_SCL_LO; + } + + // Return value will only be evaluated when checking device ACK + return (sda == 0); +} + +// ************************************************************************************************* +// @fn ps_i2c_write +// @brief Clock out bits through SDA. +// @param uint8_t data Byte to send +// @return none +// ************************************************************************************************* +void ps_i2c_write(uint8_t data) +{ + uint8_t i, mask; + + // Set mask byte to 10000000b + mask = BIT0 << 7; + + PS_I2C_SDA_OUT; // SDA is output + + for (i = 8; i > 0; i--) + { + PS_I2C_SCL_LO; // SCL=0 + if ((data & mask) == mask) + { + PS_I2C_SDA_HI; // SDA=1 + } + else + { + PS_I2C_SDA_LO; // SDA=0 + } + mask = mask >> 1; + ps_i2c_delay(); + PS_I2C_SCL_HI; // SCL=1 + ps_i2c_delay(); + } + + PS_I2C_SCL_LO; // SCL=0 + PS_I2C_SDA_IN; // SDA is input +} + +// ************************************************************************************************* +// @fn ps_i2c_read +// @brief Read bits from SDA +// @param uint8_t ack 1=Send ACK after read, 0=Send NACK after read +// @return uint8_t Bits read +// ************************************************************************************************* +uint8_t ps_i2c_read(uint8_t ack) +{ + uint8_t i; + uint8_t data = 0; + + PS_I2C_SDA_IN; // SDA is input + + for (i = 0; i < 8; i++) + { + PS_I2C_SCL_LO; // SCL=0 + ps_i2c_delay(); + PS_I2C_SCL_HI; // SCL=0 + ps_i2c_delay(); + + // Shift captured bits to left + data = data << 1; + + // Capture new bit + if ((PS_I2C_IN & PS_SDA_PIN) == PS_SDA_PIN) + data |= BIT0; + } + + PS_I2C_SDA_OUT; // SDA is output + + // 1 aditional clock phase to generate master ACK + PS_I2C_SCL_LO; // SCL=0 + if (ack == 1) + PS_I2C_SDA_LO // Send ack -> continue read + else + PS_I2C_SDA_HI // Send nack -> stop read + ps_i2c_delay(); + PS_I2C_SCL_HI; // SCL=0 + ps_i2c_delay(); + PS_I2C_SCL_LO; + + return (data); +} + +// ************************************************************************************************* +// @fn as_write_register +// @brief Write a byte to the pressure sensor +// @param uint8_t device Device address +// uint8_t address Register address +// uint8_t data Data to write +// @return uint8_t +// ************************************************************************************************* +uint8_t ps_write_register(uint8_t device, uint8_t address, uint8_t data) +{ + volatile uint8_t success; + + ps_i2c_sda(PS_I2C_SEND_START); // Generate start condition + + ps_i2c_write(device | PS_I2C_WRITE); // Send 7bit device address + r/w bit '0' -> write + success = ps_i2c_sda(PS_I2C_CHECK_ACK); // Check ACK from device + if (!success) + return (0); + + ps_i2c_write(address); // Send 8bit register address + success = ps_i2c_sda(PS_I2C_CHECK_ACK); // Check ACK from device + if (!success) + return (0); + + ps_i2c_write(data); // Send 8bit data to register + success = ps_i2c_sda(PS_I2C_CHECK_ACK); // Check ACK from device + // Slave does not send this ACK + // if (!success) return (0); + + ps_i2c_sda(PS_I2C_SEND_STOP); // Generate stop condition + + return (1); +} + +// ************************************************************************************************* +// @fn ps_read_register +// @brief Read a byte from the pressure sensor +// @param uint8_t device Device address +// uint8_t address Register address +// uint8_t mode PS_I2C_8BIT_ACCESS, PS_I2C_16BIT_ACCESS +// @return uint16_t Register content +// ************************************************************************************************* +uint16_t ps_read_register(uint8_t device, uint8_t address, uint8_t mode) +{ + uint8_t success; + uint16_t data = 0; + + ps_i2c_sda(PS_I2C_SEND_START); // Generate start condition + + ps_i2c_write(device | PS_I2C_WRITE); // Send 7bit device address + r/w bit '0' -> write + success = ps_i2c_sda(PS_I2C_CHECK_ACK); // Check ACK from device + if (!success) + return (0); + + ps_i2c_write(address); // Send 8bit register address + success = ps_i2c_sda(PS_I2C_CHECK_ACK); // Check ACK from device + if (!success) + return (0); + + ps_i2c_sda(PS_I2C_SEND_RESTART); // Generate restart condition + + ps_i2c_write(device | PS_I2C_READ); // Send 7bit device address + r/w bit '1' -> read + success = ps_i2c_sda(PS_I2C_CHECK_ACK); // Check ACK from device + if (!success) + return (0); + + if (mode == PS_I2C_16BIT_ACCESS) + { + data = ps_i2c_read(1) << 8; // Read MSB 8bit data from register + data |= ps_i2c_read(0); // Read LSB 8bit data from register + } + else + { + data = ps_i2c_read(0); // Read 8bit data from register + } + + ps_i2c_sda(PS_I2C_SEND_STOP); // Generate stop condition + + return (data); +} + +// ************************************************************************************************* +// @fn ps_i2c_delay +// @brief Delay between I2C signal edges. +// @param none +// @return none +// ************************************************************************************************* +void ps_i2c_delay(void) +{ + asm (" nop"); +} + +// ************************************************************************************************* +// @fn init_pressure_table +// @brief Init pressure table with constants +// @param uint32_t p Pressure (Pa) +// @return uint16_t Altitude (m) +// ************************************************************************************************* +void init_pressure_table(void) +{ + uint8_t i; + + for (i = 0; i < 17; i++) + p[i] = p0[i]; +} + +// ************************************************************************************************* +// @fn update_pressure_table +// @brief Calculate pressure table for reference altitude. +// Implemented straight from VTI reference code. +// @param int16_t href Reference height +// uint32_t p_meas Pressure (Pa) +// uint16_t t_meas Temperature (10*K) +// @return none +// ************************************************************************************************* +void update_pressure_table(int16_t href, uint32_t p_meas, uint16_t t_meas) +{ + const float Invt00 = 0.003470415; + const float coefp = 0.00006; + volatile float p_fact; + volatile float p_noll; + volatile float hnoll; + volatile float h_low = 0; + volatile float t0; + uint8_t i; + + // Typecast arguments + volatile float fl_href = href; + volatile float fl_p_meas = (float)p_meas / 100; // Convert from Pa to hPa + volatile float fl_t_meas = (float)t_meas / 10; // Convert from 10 K to 1 K + + t0 = fl_t_meas + (0.0065 * fl_href); + + hnoll = fl_href / (t0 * Invt00); + + for (i = 0; i <= 15; i++) + { + if (h0[i] > hnoll) + break; + h_low = h0[i]; + } + + p_noll = + (float)(hnoll - + h_low) * + (1 - + (hnoll - + (float)h0[i]) * + coefp) * ((float)p0[i] - (float)p0[i - 1]) / ((float)h0[i] - h_low) + (float)p0[i - 1]; + + // Calculate multiplicator + p_fact = fl_p_meas / p_noll; + + // Apply correction factor to pressure table + for (i = 0; i <= 16; i++) + { + p[i] = p0[i] * p_fact; + } +} + +// ************************************************************************************************* +// @fn conv_pa_to_meter +// @brief Convert pressure (Pa) to altitude (m) using a conversion table +// Implemented straight from VTI reference code. +// @param uint32_t p_meas Pressure (Pa) +// uint16_t t_meas Temperature (10*K) +// @return int16_t Altitude (m) +// ************************************************************************************************* +int16_t conv_pa_to_meter(uint32_t p_meas, uint16_t t_meas) +{ + const float coef2 = 0.0007; + const float Invt00 = 0.003470415; + volatile float hnoll; + volatile float t0; + volatile float p_low; + volatile float fl_h; + volatile int16_t h; + uint8_t i; + + // Typecast arguments + volatile float fl_p_meas = (float)p_meas / 100; // Convert from Pa to hPa + volatile float fl_t_meas = (float)t_meas / 10; // Convert from 10 K to 1 K + + for (i = 0; i <= 16; i++) + { + if (p[i] < fl_p_meas) + break; + p_low = p[i]; + } + + if (i == 0) + { + hnoll = (float)(fl_p_meas - p[0]) / (p[1] - p[0]) * ((float)(h0[1] - h0[0])); + } + else if (i < 15) + { + hnoll = + (float)(fl_p_meas - + p_low) * + (1 - + (fl_p_meas - + p[i]) * coef2) / (p[i] - p_low) * ((float)(h0[i] - h0[i - 1])) + h0[i - 1]; + } + else if (i == 15) + { + hnoll = + (float)(fl_p_meas - p_low) / (p[i] - p_low) * ((float)(h0[i] - h0[i - 1])) + h0[i - 1]; + } + else // i==16 + { + hnoll = (float)(fl_p_meas - p[16]) / (p[16] - p[15]) * ((float)(h0[16] - h0[15])) + h0[16]; + } + + // Compensate temperature error + t0 = fl_t_meas / (1 - hnoll * Invt00 * 0.0065); + fl_h = Invt00 * t0 * hnoll; + h = (uint16_t) fl_h; + + return (h); +} + diff --git a/drivers/ps.h b/drivers/ps.h new file mode 100644 index 0000000..285208f --- /dev/null +++ b/drivers/ps.h @@ -0,0 +1,103 @@ +// ************************************************************************************************* +// +// Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the +// distribution. +// +// Neither the name of Texas Instruments Incorporated nor the names of +// its contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// ************************************************************************************************* + +#ifndef PS_H_ +#define PS_H_ + +// ************************************************************************************************* +// Include section + +// ************************************************************************************************* +// Prototypes section +extern void ps_init(void); +extern uint8_t ps_i2c_sda(uint8_t ack); +extern void ps_i2c_delay(void); +extern void ps_i2c_write(uint8_t data); +extern uint8_t ps_i2c_read(uint8_t ack); +extern uint8_t ps_write_register(uint8_t device, uint8_t address, uint8_t data); +extern uint16_t ps_read_register(uint8_t device, uint8_t address, uint8_t mode); +extern void init_pressure_table(void); +extern void update_pressure_table(int16_t href, uint32_t p_meas, uint16_t t_meas); +extern int16_t conv_pa_to_meter(uint32_t p_meas, uint16_t t_meas); + +volatile uint8_t ps_last_interrupt; + +// ************************************************************************************************* +// Defines section + +// Port and pin resource for I2C interface to pressure sensor +// SCL=PJ.3, SDA=PJ.2, EOC=P2.6 +#define PS_I2C_IN (PJIN) +#define PS_I2C_OUT (PJOUT) +#define PS_I2C_DIR (PJDIR) +#define PS_I2C_REN (PJREN) +#define PS_SCL_PIN (BIT3) +#define PS_SDA_PIN (BIT2) + +// Port, pin and interrupt resource for interrupt from acceleration sensor, EOC=P2.6 +#define PS_INT_IN (P2IN) +#define PS_INT_OUT (P2OUT) +#define PS_INT_DIR (P2DIR) +#define PS_INT_IE (P2IE) +#define PS_INT_IES (P2IES) +#define PS_INT_IFG (P2IFG) +#define PS_INT_PIN (BIT6) + +// I2C defines +#define PS_I2C_WRITE (0u) +#define PS_I2C_READ (1u) + +#define PS_I2C_SEND_START (0u) +#define PS_I2C_SEND_RESTART (1u) +#define PS_I2C_SEND_STOP (2u) +#define PS_I2C_CHECK_ACK (3u) + +#define PS_I2C_8BIT_ACCESS (0u) +#define PS_I2C_16BIT_ACCESS (1u) + +#define PS_I2C_SCL_HI { PS_I2C_OUT |= PS_SCL_PIN; } +#define PS_I2C_SCL_LO { PS_I2C_OUT &= ~PS_SCL_PIN; } +#define PS_I2C_SDA_HI { PS_I2C_OUT |= PS_SDA_PIN; } +#define PS_I2C_SDA_LO { PS_I2C_OUT &= ~PS_SDA_PIN; } +#define PS_I2C_SDA_IN { PS_I2C_OUT |= PS_SDA_PIN; PS_I2C_DIR &= ~PS_SDA_PIN; } +#define PS_I2C_SDA_OUT { PS_I2C_DIR |= PS_SDA_PIN; } + +// ************************************************************************************************* +// Global Variable section + +// ************************************************************************************************* +// Extern section + +#endif /*PS_H_ */ diff --git a/drivers/radio.c b/drivers/radio.c index 4265b6d..9e82c0e 100644 --- a/drivers/radio.c +++ b/drivers/radio.c @@ -55,21 +55,21 @@ extern void MRFI_RadioIsr(void); // ************************************************************************************************* void radio_reset(void) { - volatile uint16_t i; - uint8_t x; + volatile uint16_t i; + uint8_t x; - // Reset radio core - Strobe(RF_SRES); + // Reset radio core + Strobe(RF_SRES); - // Wait before checking IDLE - for (i = 0; i < 100; i++); + // Wait before checking IDLE + for (i = 0; i < 100; i++); - do { - x = Strobe(RF_SIDLE); - } while ((x & 0x70) != 0x00); + do { + x = Strobe(RF_SIDLE); + } while ((x & 0x70) != 0x00); - // Clear radio error register - RF1AIFERR = 0; + // Clear radio error register + RF1AIFERR = 0; } @@ -81,13 +81,13 @@ void radio_reset(void) // ************************************************************************************************* void radio_powerdown(void) { - /* Chip bug: Radio does not come out of this SLEEP when put to sleep - * using the SPWD cmd. However, it does wakes up if SXOFF was used to - * put it to sleep. - */ - // Powerdown radio - Strobe(RF_SIDLE); - Strobe(RF_SPWD); + /* Chip bug: Radio does not come out of this SLEEP when put to sleep + * using the SPWD cmd. However, it does wakes up if SXOFF was used to + * put it to sleep. + */ + // Powerdown radio + Strobe(RF_SIDLE); + Strobe(RF_SPWD); } @@ -100,13 +100,13 @@ void radio_powerdown(void) // ************************************************************************************************* void radio_sxoff(void) { - /* Chip bug: Radio does not come out of this SLEEP when put to sleep - * using the SPWD cmd. However, it does wakes up if SXOFF was used to - * put it to sleep. - */ - // Powerdown radio - Strobe(RF_SIDLE); - Strobe(RF_SXOFF); + /* Chip bug: Radio does not come out of this SLEEP when put to sleep + * using the SPWD cmd. However, it does wakes up if SXOFF was used to + * put it to sleep. + */ + // Powerdown radio + Strobe(RF_SIDLE); + Strobe(RF_SXOFF); } @@ -118,12 +118,12 @@ void radio_sxoff(void) // ************************************************************************************************* void open_radio(void) { - // Reset radio core - radio_reset(); + // Reset radio core + radio_reset(); - // Enable radio IRQ - RF1AIFG &= ~BIT4; // Clear a pending interrupt - RF1AIE |= BIT4; // Enable the interrupt + // Enable radio IRQ + RF1AIFG &= ~BIT4; // Clear a pending interrupt + RF1AIE |= BIT4; // Enable the interrupt } @@ -137,15 +137,15 @@ void open_radio(void) // ************************************************************************************************* void close_radio(void) { - // Disable radio IRQ - RF1AIFG = 0; - RF1AIE = 0; + // Disable radio IRQ + RF1AIFG = 0; + RF1AIE = 0; - // Reset radio core - radio_reset(); + // Reset radio core + radio_reset(); - // Put radio to sleep - radio_powerdown(); + // Put radio to sleep + radio_powerdown(); } @@ -160,14 +160,14 @@ void close_radio(void) __attribute__((interrupt(CC1101_VECTOR))) void radio_ISR(void) { - uint8_t rf1aivec = RF1AIV; - - // Forward to SimpliciTI interrupt service routine - /*if (is_rf()) { - MRFI_RadioIsr(); - } else {*/ - if (rf1aivec == RF1AIV_NONE) { // RF1A interface interrupt (error etc.) - asm(" nop"); // break here - } - /*}*/ + uint8_t rf1aivec = RF1AIV; + + // Forward to SimpliciTI interrupt service routine + /*if (is_rf()) { + MRFI_RadioIsr(); + } else {*/ + if (rf1aivec == RF1AIV_NONE) { // RF1A interface interrupt (error etc.) + asm(" nop"); // break here + } + /*}*/ } diff --git a/drivers/rf1a.c b/drivers/rf1a.c index ba20869..1ad6c01 100644 --- a/drivers/rf1a.c +++ b/drivers/rf1a.c @@ -33,49 +33,49 @@ // ************************************************************************************************* unsigned char Strobe(unsigned char strobe) { - uint8_t statusByte = 0; - uint16_t int_state, gdo_state; + uint8_t statusByte = 0; + uint16_t int_state, gdo_state; - // Check for valid strobe command - if ((strobe == 0xBD) || ((strobe > RF_SRES) && (strobe < RF_SNOP))) { - ENTER_CRITICAL_SECTION(int_state); + // Check for valid strobe command + if ((strobe == 0xBD) || ((strobe > RF_SRES) && (strobe < RF_SNOP))) { + ENTER_CRITICAL_SECTION(int_state); - // Clear the Status read flag - RF1AIFCTL1 &= ~(RFSTATIFG); + // Clear the Status read flag + RF1AIFCTL1 &= ~(RFSTATIFG); - // Wait for radio to be ready for next instruction - while (!(RF1AIFCTL1 & RFINSTRIFG)); + // Wait for radio to be ready for next instruction + while (!(RF1AIFCTL1 & RFINSTRIFG)); - // Write the strobe instruction - if ((strobe > RF_SRES) && (strobe < RF_SNOP)) { + // Write the strobe instruction + if ((strobe > RF_SRES) && (strobe < RF_SNOP)) { - gdo_state = ReadSingleReg(IOCFG2); // buffer IOCFG2 state - WriteSingleReg(IOCFG2, 0x29); // c-ready to GDO2 + gdo_state = ReadSingleReg(IOCFG2); // buffer IOCFG2 state + WriteSingleReg(IOCFG2, 0x29); // c-ready to GDO2 - RF1AINSTRB = strobe; + RF1AINSTRB = strobe; - if ((RF1AIN & 0x04) == 0x04) { // chip at sleep mode - if ((strobe == RF_SXOFF) || (strobe == RF_SPWD) || (strobe == RF_SWOR)) { } - else { - while ((RF1AIN & 0x04) == 0x04); // c-ready ? + if ((RF1AIN & 0x04) == 0x04) { // chip at sleep mode + if ((strobe == RF_SXOFF) || (strobe == RF_SPWD) || (strobe == RF_SWOR)) { } + else { + while ((RF1AIN & 0x04) == 0x04); // c-ready ? - __delay_cycles(9800); // Delay for ~810usec at 12MHz CPU clock - } - } + __delay_cycles(9800); // Delay for ~810usec at 12MHz CPU clock + } + } - WriteSingleReg(IOCFG2, gdo_state); // restore IOCFG2 setting - } else { // chip active mode - RF1AINSTRB = strobe; - } + WriteSingleReg(IOCFG2, gdo_state); // restore IOCFG2 setting + } else { // chip active mode + RF1AINSTRB = strobe; + } - statusByte = RF1ASTATB; + statusByte = RF1ASTATB; - while (!(RF1AIFCTL1 & RFSTATIFG)); + while (!(RF1AIFCTL1 & RFSTATIFG)); - EXIT_CRITICAL_SECTION(int_state); - } + EXIT_CRITICAL_SECTION(int_state); + } - return statusByte; + return statusByte; } @@ -87,8 +87,8 @@ unsigned char Strobe(unsigned char strobe) // ************************************************************************************************* void ResetRadioCore(void) { - Strobe(RF_SRES); // Reset the Radio Core - Strobe(RF_SNOP); // Reset Radio Pointer + Strobe(RF_SRES); // Reset the Radio Core + Strobe(RF_SNOP); // Reset Radio Pointer } @@ -100,17 +100,17 @@ void ResetRadioCore(void) // ************************************************************************************************* unsigned char ReadSingleReg(unsigned char addr) { - unsigned char x; - uint16_t int_state; + unsigned char x; + uint16_t int_state; - ENTER_CRITICAL_SECTION(int_state); + ENTER_CRITICAL_SECTION(int_state); - RF1AINSTR1B = (addr | RF_REGRD); - x = RF1ADOUT1B; + RF1AINSTR1B = (addr | RF_REGRD); + x = RF1ADOUT1B; - EXIT_CRITICAL_SECTION(int_state); + EXIT_CRITICAL_SECTION(int_state); - return x; + return x; } @@ -122,20 +122,20 @@ unsigned char ReadSingleReg(unsigned char addr) // ************************************************************************************************* void WriteSingleReg(unsigned char addr, unsigned char value) { - __attribute__((unused)) volatile unsigned int i; - uint16_t int_state; + __attribute__((unused)) volatile unsigned int i; + uint16_t int_state; - ENTER_CRITICAL_SECTION(int_state); + ENTER_CRITICAL_SECTION(int_state); - while (!(RF1AIFCTL1 & RFINSTRIFG)); // Wait for the Radio to be ready for the next instruction + while (!(RF1AIFCTL1 & RFINSTRIFG)); // Wait for the Radio to be ready for the next instruction - RF1AINSTRW = ((addr | RF_REGWR) << 8) + value; // Send address + Instruction + RF1AINSTRW = ((addr | RF_REGWR) << 8) + value; // Send address + Instruction - while (!(RFDINIFG & RF1AIFCTL1)); + while (!(RFDINIFG & RF1AIFCTL1)); - i = RF1ADOUTB; // Reset RFDOUTIFG flag which contains status byte + i = RF1ADOUTB; // Reset RFDOUTIFG flag which contains status byte - EXIT_CRITICAL_SECTION(int_state); + EXIT_CRITICAL_SECTION(int_state); } @@ -147,25 +147,25 @@ void WriteSingleReg(unsigned char addr, unsigned char value) // ************************************************************************************************* void ReadBurstReg(unsigned char addr, unsigned char *buffer, unsigned char count) { - unsigned int i; - uint16_t int_state; + unsigned int i; + uint16_t int_state; - ENTER_CRITICAL_SECTION(int_state); + ENTER_CRITICAL_SECTION(int_state); - while (!(RF1AIFCTL1 & RFINSTRIFG)); // Wait for the Radio to be ready for next instruction + while (!(RF1AIFCTL1 & RFINSTRIFG)); // Wait for the Radio to be ready for next instruction - RF1AINSTR1B = (addr | RF_REGRD); // Send address + Instruction + RF1AINSTR1B = (addr | RF_REGRD); // Send address + Instruction - for (i = 0; i < (count - 1); i++) { - while (!(RFDOUTIFG & RF1AIFCTL1)); // Wait for the Radio Core to update the RF1ADOUTB reg + for (i = 0; i < (count - 1); i++) { + while (!(RFDOUTIFG & RF1AIFCTL1)); // Wait for the Radio Core to update the RF1ADOUTB reg - buffer[i] = RF1ADOUT1B; // Read DOUT from Radio Core + clears RFDOUTIFG - // Also initiates auo-read for next DOUT byte - } + buffer[i] = RF1ADOUT1B; // Read DOUT from Radio Core + clears RFDOUTIFG + // Also initiates auo-read for next DOUT byte + } - buffer[count - 1] = RF1ADOUT0B; // Store the last DOUT from Radio Core + buffer[count - 1] = RF1ADOUT0B; // Store the last DOUT from Radio Core - EXIT_CRITICAL_SECTION(int_state); + EXIT_CRITICAL_SECTION(int_state); } @@ -177,25 +177,25 @@ void ReadBurstReg(unsigned char addr, unsigned char *buffer, unsigned char count // ************************************************************************************************* void WriteBurstReg(unsigned char addr, unsigned char *buffer, unsigned char count) { - // Write Burst works wordwise not bytewise - bug known already - unsigned char i; - uint16_t int_state; + // Write Burst works wordwise not bytewise - bug known already + unsigned char i; + uint16_t int_state; - ENTER_CRITICAL_SECTION(int_state); + ENTER_CRITICAL_SECTION(int_state); - while (!(RF1AIFCTL1 & RFINSTRIFG)); // Wait for the Radio to be ready for next instruction + while (!(RF1AIFCTL1 & RFINSTRIFG)); // Wait for the Radio to be ready for next instruction - RF1AINSTRW = ((addr | RF_REGWR) << 8) + buffer[0]; // Send address + Instruction + RF1AINSTRW = ((addr | RF_REGWR) << 8) + buffer[0]; // Send address + Instruction - for (i = 1; i < count; i++) { - RF1ADINB = buffer[i]; // Send data + for (i = 1; i < count; i++) { + RF1ADINB = buffer[i]; // Send data - while (!(RFDINIFG & RF1AIFCTL1)); // Wait for TX to finish - } + while (!(RFDINIFG & RF1AIFCTL1)); // Wait for TX to finish + } - i = RF1ADOUTB; // Reset RFDOUTIFG flag which contains status byte + i = RF1ADOUTB; // Reset RFDOUTIFG flag which contains status byte - EXIT_CRITICAL_SECTION(int_state); + EXIT_CRITICAL_SECTION(int_state); } @@ -207,39 +207,39 @@ void WriteBurstReg(unsigned char addr, unsigned char *buffer, unsigned char coun // ************************************************************************************************* void WritePATable(unsigned char value) { - unsigned char readbackPATableValue = 0; - uint16_t int_state; + unsigned char readbackPATableValue = 0; + uint16_t int_state; - ENTER_CRITICAL_SECTION(int_state); + ENTER_CRITICAL_SECTION(int_state); - while (readbackPATableValue != value) { - while (!(RF1AIFCTL1 & RFINSTRIFG)); + while (readbackPATableValue != value) { + while (!(RF1AIFCTL1 & RFINSTRIFG)); - RF1AINSTRW = 0x7E00 + value; // PA Table write (burst) + RF1AINSTRW = 0x7E00 + value; // PA Table write (burst) - while (!(RF1AIFCTL1 & RFINSTRIFG)); + while (!(RF1AIFCTL1 & RFINSTRIFG)); - RF1AINSTRB = RF_SNOP; // reset pointer + RF1AINSTRB = RF_SNOP; // reset pointer - while (!(RF1AIFCTL1 & RFINSTRIFG)); + while (!(RF1AIFCTL1 & RFINSTRIFG)); - RF1AINSTRB = 0xFE; // PA Table read (burst) + RF1AINSTRB = 0xFE; // PA Table read (burst) - while (!(RF1AIFCTL1 & RFDINIFG)); + while (!(RF1AIFCTL1 & RFDINIFG)); - RF1ADINB = 0x00; //dummy write + RF1ADINB = 0x00; //dummy write - while (!(RF1AIFCTL1 & RFDOUTIFG)); + while (!(RF1AIFCTL1 & RFDOUTIFG)); - readbackPATableValue = RF1ADOUT0B; + readbackPATableValue = RF1ADOUT0B; - while (!(RF1AIFCTL1 & RFINSTRIFG)); + while (!(RF1AIFCTL1 & RFINSTRIFG)); - RF1AINSTRB = RF_SNOP; - } + RF1AINSTRB = RF_SNOP; + } - EXIT_CRITICAL_SECTION(int_state); + EXIT_CRITICAL_SECTION(int_state); } diff --git a/drivers/rtc_dst.c b/drivers/rtc_dst.c index 84415ad..187ba96 100644 --- a/drivers/rtc_dst.c +++ b/drivers/rtc_dst.c @@ -1,25 +1,25 @@ /** - Daylight Saving Time for OpenChronos on the TI ez430 chronos watch. + Daylight Saving Time for OpenChronos on the TI ez430 chronos watch. - Copyright 2011 Rick Miller - Copyright 2012 Dan Ellis + Copyright 2011 Rick Miller + Copyright 2012 Dan Ellis - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ #include "openchronos.h" @@ -49,8 +49,8 @@ uint8_t rtc_dst_day_of_week(uint16_t year, uint8_t month, uint8_t day); /****************************************************************************/ void rtc_dst_init(void) { - /* Calculate when to switch dates */ - rtc_dst_calculate_dates(rtca_time.year, rtca_time.mon, rtca_time.day, rtca_time.hour); + /* Calculate when to switch dates */ + rtc_dst_calculate_dates(rtca_time.year, rtca_time.mon, rtca_time.day, rtca_time.hour); } /******************************************************************************/ @@ -59,25 +59,25 @@ void rtc_dst_init(void) /******************************************************************************/ void rtc_dst_hourly_update(void) { - if (rtca_time.hour == 2) { - /* time changes always occur at 2AM */ - if (rtc_dst_state == RTC_DST_STATE_ST) { - if (rtca_time.mon == rtc_dst_dates[0].month && rtca_time.day == rtc_dst_dates[0].day) { - /* spring forward */ - rtc_dst_state = RTC_DST_STATE_DST; - rtca_time.hour++; - rtca_set_time(); - } - } else { - /* rtc_dst_state == RTC_DST_STATE_DST */ - if (rtca_time.mon == rtc_dst_dates[1].month && rtca_time.day == rtc_dst_dates[1].day) { - /* fall back */ - rtc_dst_state = RTC_DST_STATE_ST; - rtca_time.hour--; - rtca_set_time(); - } - } - } + if (rtca_time.hour == 2) { + /* time changes always occur at 2AM */ + if (rtc_dst_state == RTC_DST_STATE_ST) { + if (rtca_time.mon == rtc_dst_dates[0].month && rtca_time.day == rtc_dst_dates[0].day) { + /* spring forward */ + rtc_dst_state = RTC_DST_STATE_DST; + rtca_time.hour++; + rtca_set_time(); + } + } else { + /* rtc_dst_state == RTC_DST_STATE_DST */ + if (rtca_time.mon == rtc_dst_dates[1].month && rtca_time.day == rtc_dst_dates[1].day) { + /* fall back */ + rtc_dst_state = RTC_DST_STATE_ST; + rtca_time.hour--; + rtca_set_time(); + } + } + } } /********************************************************************************/ @@ -92,128 +92,128 @@ void rtc_dst_calculate_dates(uint16_t year, uint8_t month, uint8_t day, uint8_t { #if (CONFIG_RTC_DST_ZONE == DST_US) - // DST in US/Canada: 2nd Sun in Mar to 1st Sun in Nov. - rtc_dst_dates[0].month = 3; - rtc_dst_dates[0].day = N_SUN_OF_MON(2, 3, year); - rtc_dst_dates[1].month = 11; - rtc_dst_dates[1].day = N_SUN_OF_MON(1, 11, year); + // DST in US/Canada: 2nd Sun in Mar to 1st Sun in Nov. + rtc_dst_dates[0].month = 3; + rtc_dst_dates[0].day = N_SUN_OF_MON(2, 3, year); + rtc_dst_dates[1].month = 11; + rtc_dst_dates[1].day = N_SUN_OF_MON(1, 11, year); #endif #if (CONFIG_RTC_DST_ZONE == DST_MEX) - // DST in Mexico: first Sun in Apr to last Sun in Oct. - rtc_dst_dates[0].month = 4; - rtc_dst_dates[0].day = N_SUN_OF_MON(1, 4, year); - rtc_dst_dates[1].month = 10; - rtc_dst_dates[1].day = LAST_SUN_OF_MON(10, 31, year); + // DST in Mexico: first Sun in Apr to last Sun in Oct. + rtc_dst_dates[0].month = 4; + rtc_dst_dates[0].day = N_SUN_OF_MON(1, 4, year); + rtc_dst_dates[1].month = 10; + rtc_dst_dates[1].day = LAST_SUN_OF_MON(10, 31, year); #endif #if (CONFIG_RTC_DST_ZONE == DST_BRZ) - // DST in Brazil: third Sun in Oct to third Sun in Feb. - rtc_dst_dates[0].month = 10; - rtc_dst_dates[0].day = N_SUN_OF_MON(3, 10, year); - rtc_dst_dates[1].month = 2; - rtc_dst_dates[1].day = N_SUN_OF_MON(3, 2, year); + // DST in Brazil: third Sun in Oct to third Sun in Feb. + rtc_dst_dates[0].month = 10; + rtc_dst_dates[0].day = N_SUN_OF_MON(3, 10, year); + rtc_dst_dates[1].month = 2; + rtc_dst_dates[1].day = N_SUN_OF_MON(3, 2, year); #endif #if (CONFIG_RTC_DST_ZONE == DST_EU) - // DST in EU/UK: last Sun in Mar to last Sun in Oct. - rtc_dst_dates[0].month = 3; - rtc_dst_dates[0].day = LAST_SUN_OF_MON(3, 31, year); - rtc_dst_dates[1].month = 10; - rtc_dst_dates[1].day = LAST_SUN_OF_MON(10, 31, year); + // DST in EU/UK: last Sun in Mar to last Sun in Oct. + rtc_dst_dates[0].month = 3; + rtc_dst_dates[0].day = LAST_SUN_OF_MON(3, 31, year); + rtc_dst_dates[1].month = 10; + rtc_dst_dates[1].day = LAST_SUN_OF_MON(10, 31, year); #endif #if (CONFIG_RTC_DST_ZONE == DST_AUS) - // DST in Australia: first Sun in Oct to first Sun in Apr. - rtc_dst_dates[0].month = 10; - rtc_dst_dates[0].day = N_SUN_OF_MON(1, 10, year); - rtc_dst_dates[1].month = 4; - rtc_dst_dates[1].day = N_SUN_OF_MON(1, 4, year); + // DST in Australia: first Sun in Oct to first Sun in Apr. + rtc_dst_dates[0].month = 10; + rtc_dst_dates[0].day = N_SUN_OF_MON(1, 10, year); + rtc_dst_dates[1].month = 4; + rtc_dst_dates[1].day = N_SUN_OF_MON(1, 4, year); #endif #if (CONFIG_RTC_DST_ZONE == DST_NZ) - // DST in New Zealand: last Sun in Sep to first Sun in Apr. - rtc_dst_dates[0].month = 9; - rtc_dst_dates[0].day = LAST_SUN_OF_MON(9, 30, year); - rtc_dst_dates[1].month = 4; - rtc_dst_dates[1].day = N_SUN_OF_MON(1, 4, year); + // DST in New Zealand: last Sun in Sep to first Sun in Apr. + rtc_dst_dates[0].month = 9; + rtc_dst_dates[0].day = LAST_SUN_OF_MON(9, 30, year); + rtc_dst_dates[1].month = 4; + rtc_dst_dates[1].day = N_SUN_OF_MON(1, 4, year); #endif - // This test may be wrong if you set your watch - // on the time-change day. - rtc_dst_state = (rtc_dst_isDateInDST(month, day, hour)) ? RTC_DST_STATE_DST : RTC_DST_STATE_ST; + // This test may be wrong if you set your watch + // on the time-change day. + rtc_dst_state = (rtc_dst_isDateInDST(month, day, hour)) ? RTC_DST_STATE_DST : RTC_DST_STATE_ST; } /* Figure out if the specified hour on the specified day is within the DST range */ uint8_t rtc_dst_isDateInDST(uint8_t month, uint8_t day, uint8_t hour) { - /* clip hour to a single digit since we only care which side of 2AM it is */ - /* and we're going to do comparisons via a MMDDH integer in 16 bits */ - if (hour > 9) hour = 9; - - if (rtc_dst_dates[0].month < rtc_dst_dates[1].month) { - /* Northern hemisphere */ - return - ((DSTNUM(month, day, hour) >= DSTNUM(rtc_dst_dates[0].month, rtc_dst_dates[0].day, 2)) && - (DSTNUM(month, day, hour) < DSTNUM(rtc_dst_dates[1].month, rtc_dst_dates[1].day, 2))); - } else { - /* Southern hemisphere */ - return (!( - ((DSTNUM(month, day, hour) >= DSTNUM(rtc_dst_dates[1].month, rtc_dst_dates[1].day,2)) && - (DSTNUM(month, day, hour) < DSTNUM(rtc_dst_dates[0].month, rtc_dst_dates[0].day,2))))); - } + /* clip hour to a single digit since we only care which side of 2AM it is */ + /* and we're going to do comparisons via a MMDDH integer in 16 bits */ + if (hour > 9) hour = 9; + + if (rtc_dst_dates[0].month < rtc_dst_dates[1].month) { + /* Northern hemisphere */ + return + ((DSTNUM(month, day, hour) >= DSTNUM(rtc_dst_dates[0].month, rtc_dst_dates[0].day, 2)) && + (DSTNUM(month, day, hour) < DSTNUM(rtc_dst_dates[1].month, rtc_dst_dates[1].day, 2))); + } else { + /* Southern hemisphere */ + return (!( + ((DSTNUM(month, day, hour) >= DSTNUM(rtc_dst_dates[1].month, rtc_dst_dates[1].day,2)) && + (DSTNUM(month, day, hour) < DSTNUM(rtc_dst_dates[0].month, rtc_dst_dates[0].day,2))))); + } } uint8_t rtc_dst_day_of_week(uint16_t year, uint8_t month, uint8_t day) { - /* Calculate days since 2000-01-01 */ - uint32_t tmp = (year % 200) * 365; - tmp += (((year % 200) + 3) / 4); // leap days + /* Calculate days since 2000-01-01 */ + uint32_t tmp = (year % 200) * 365; + tmp += (((year % 200) + 3) / 4); // leap days - switch (month) { // using lots of drop-through! - case 12: - tmp += 30; /* for nov */ + switch (month) { // using lots of drop-through! + case 12: + tmp += 30; /* for nov */ - case 11: - tmp += 31; /* for oct */ + case 11: + tmp += 31; /* for oct */ - case 10: - tmp += 30; /* for sep */ + case 10: + tmp += 30; /* for sep */ - case 9: - tmp += 31; /* for aug */ + case 9: + tmp += 31; /* for aug */ - case 8: - tmp += 31; /* for jul */ + case 8: + tmp += 31; /* for jul */ - case 7: - tmp += 30; /* for jun */ + case 7: + tmp += 30; /* for jun */ - case 6: - tmp += 31; /* for may */ + case 6: + tmp += 31; /* for may */ - case 5: - tmp += 30; /* for apr */ + case 5: + tmp += 30; /* for apr */ - case 4: - tmp += 31; /* for mar */ + case 4: + tmp += 31; /* for mar */ - case 3: - tmp += 28; /* for feb */ + case 3: + tmp += 28; /* for feb */ - if ((year % 4) == 0) { - tmp++; - } + if ((year % 4) == 0) { + tmp++; + } - case 2: - tmp += 31; /* for jan */ + case 2: + tmp += 31; /* for jan */ - case 1: - default: - /* do nothing */ - break; - } + case 1: + default: + /* do nothing */ + break; + } - tmp += day; - tmp--; /* because day-of-month is 1-based (2000-01-01 is the ZERO day). */ + tmp += day; + tmp--; /* because day-of-month is 1-based (2000-01-01 is the ZERO day). */ - /* day zero (2000-01-01) was a Saturday. */ - return (uint8_t)((tmp + 6) % 7); + /* day zero (2000-01-01) was a Saturday. */ + return (uint8_t)((tmp + 6) % 7); } #endif /* CONFIG_RTC_DST */ diff --git a/drivers/rtc_dst.h b/drivers/rtc_dst.h index c435eec..8e92838 100644 --- a/drivers/rtc_dst.h +++ b/drivers/rtc_dst.h @@ -1,25 +1,25 @@ /** - Daylight Saving Time for OpenChronos on the TI ez430 chronos watch. + Daylight Saving Time for OpenChronos on the TI ez430 chronos watch. - Copyright 2011 Rick Miller - Copyright 2012 Dan Ellis + Copyright 2011 Rick Miller + Copyright 2012 Dan Ellis - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ #ifndef RTC_DST_H_ @@ -36,8 +36,8 @@ #define DST_NZ 6 struct rtc_dst_date_struct { - uint8_t month; - uint8_t day; + uint8_t month; + uint8_t day; }; extern struct rtc_dst_date_struct dst_dates[]; diff --git a/drivers/rtca.c b/drivers/rtca.c index 1741415..c46fff8 100644 --- a/drivers/rtca.c +++ b/drivers/rtca.c @@ -1,25 +1,25 @@ /** - rtca.c: TI CC430 Hardware Realtime Clock (RTC_A) + rtca.c: TI CC430 Hardware Realtime Clock (RTC_A) - Copyright (C) 2011-2012 Angelo Arrifano - Copyright (C) 2016 Benjamin Sølberg + Copyright (C) 2011-2012 Angelo Arrifano + Copyright (C) 2016 Benjamin Sølberg - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ #include "rtca.h" @@ -30,8 +30,8 @@ #endif /* 1. A year that is divisible by 4 is a leap year. - Exception 1: a year that is divisible by 100 is not a leap year. - Exception 2: a year that is divisible by 400 is a leap year. */ + Exception 1: a year that is divisible by 100 is not a leap year. + Exception 2: a year that is divisible by 400 is a leap year. */ #define IS_LEAP_YEAR(Y) (((Y)%4 == 0) && (((Y)%100 != 0) || ((Y)%400 == 0))) /* compute number of leap years since BASE_YEAR */ @@ -46,264 +46,264 @@ uint8_t display_am_pm = 0; void rtca_init(void) { - rtca_time.year = COMPILE_YEAR; - rtca_time.mon = COMPILE_MON; - rtca_time.day = COMPILE_DAY; - rtca_time.dow = COMPILE_DOW; - rtca_time.hour = COMPILE_HOUR; - rtca_time.min = COMPILE_MIN; - rtca_time.sec = 59; // So we can see the watch is working after reset + rtca_time.year = COMPILE_YEAR; + rtca_time.mon = COMPILE_MON; + rtca_time.day = COMPILE_DAY; + rtca_time.dow = COMPILE_DOW; + rtca_time.hour = COMPILE_HOUR; + rtca_time.min = COMPILE_MIN; + rtca_time.sec = 59; // So we can see the watch is working after reset #ifdef CONFIG_RTC_IRQ - /* Enable calendar mode (date/time registers are automatically reset) - and enable read ready interrupts - and set time event interrupts at each minute - also enable alarm interrupts */ - RTCCTL01 |= RTCMODE | RTCRDYIE | RTCAIE; - - RTCSEC = rtca_time.sec; - RTCMIN = rtca_time.min; - RTCHOUR = rtca_time.hour; - RTCDAY = rtca_time.day; - RTCDOW = rtca_time.dow; - RTCMON = rtca_time.mon; - RTCYEARL = rtca_time.year & 0xff; - RTCYEARH = rtca_time.year >> 8; - - /* Enable the RTC */ - rtca_start(); - - /* Enable minutes interrupts */ - RTCCTL01 |= RTCTEVIE; + /* Enable calendar mode (date/time registers are automatically reset) + and enable read ready interrupts + and set time event interrupts at each minute + also enable alarm interrupts */ + RTCCTL01 |= RTCMODE | RTCRDYIE | RTCAIE; + + RTCSEC = rtca_time.sec; + RTCMIN = rtca_time.min; + RTCHOUR = rtca_time.hour; + RTCDAY = rtca_time.day; + RTCDOW = rtca_time.dow; + RTCMON = rtca_time.mon; + RTCYEARL = rtca_time.year & 0xff; + RTCYEARH = rtca_time.year >> 8; + + /* Enable the RTC */ + rtca_start(); + + /* Enable minutes interrupts */ + RTCCTL01 |= RTCTEVIE; #endif #ifdef CONFIG_RTC_DST - /* initialize DST module */ - rtc_dst_init(); + /* initialize DST module */ + rtc_dst_init(); #endif } /* returns number of days for a given month */ uint8_t rtca_get_max_days(uint8_t month, uint16_t year) { - switch (month) { - case 1: - case 3: - case 5: - case 7: - case 8: - case 10: - case 12: - return 31; - - case 4: - case 6: - case 9: - case 11: - return 30; - - case 2: - if (IS_LEAP_YEAR(year)) - return 29; - else - return 28; - - default: - return 0; - } + switch (month) { + case 1: + case 3: + case 5: + case 7: + case 8: + case 10: + case 12: + return 31; + + case 4: + case 6: + case 9: + case 11: + return 30; + + case 2: + if (IS_LEAP_YEAR(year)) + return 29; + else + return 28; + + default: + return 0; + } } void rtca_set_time() { - /* Stop RTC timekeeping for a while */ - rtca_stop(); + /* Stop RTC timekeeping for a while */ + rtca_stop(); - /* update RTC registers */ - RTCSEC = rtca_time.sec; - RTCMIN = rtca_time.min; - RTCHOUR = rtca_time.hour; + /* update RTC registers */ + RTCSEC = rtca_time.sec; + RTCMIN = rtca_time.min; + RTCHOUR = rtca_time.hour; - /* Resume RTC time keeping */ - rtca_start(); + /* Resume RTC time keeping */ + rtca_start(); } void rtca_get_alarm(uint8_t *hour, uint8_t *min) { - *hour = RTCAHOUR & 0x1F; - *min = RTCAMIN & 0x3F; + *hour = RTCAHOUR & 0x1F; + *min = RTCAMIN & 0x3F; } void rtca_set_alarm(uint8_t hour, uint8_t min) { - /* Disable alarm interrupt while setting alarm */ - uint16_t original_state = RTCCTL01; - RTCCTL01 &= ~RTCAIE; - /* Set hour and min while keeping current Alarm Enable state */ - RTCAHOUR = (RTCAHOUR & RTCAE) | hour; - RTCAMIN = (RTCAMIN & RTCAE) | min; - /* Restore alarm interrupt state*/ - RTCCTL01 = original_state; + /* Disable alarm interrupt while setting alarm */ + uint16_t original_state = RTCCTL01; + RTCCTL01 &= ~RTCAIE; + /* Set hour and min while keeping current Alarm Enable state */ + RTCAHOUR = (RTCAHOUR & RTCAE) | hour; + RTCAMIN = (RTCAMIN & RTCAE) | min; + /* Restore alarm interrupt state*/ + RTCCTL01 = original_state; } void rtca_enable_alarm() { - /* Disable alarm interrupt while setting alarm */ - RTCCTL01 &= ~RTCAIE; - /* Set Alarm Enable for both hour and min */ - RTCAHOUR |= RTCAE; - RTCAMIN |= RTCAE; - /* Enable alarm interrupt */ - RTCCTL01 |= RTCAIE; + /* Disable alarm interrupt while setting alarm */ + RTCCTL01 &= ~RTCAIE; + /* Set Alarm Enable for both hour and min */ + RTCAHOUR |= RTCAE; + RTCAMIN |= RTCAE; + /* Enable alarm interrupt */ + RTCCTL01 |= RTCAIE; } void rtca_disable_alarm() { - /* Disable alarm interrupt */ - RTCCTL01 &= ~RTCAIE; - /* Clear Alarm Enable for both hour and min */ - RTCAHOUR &= ~RTCAE; - RTCAMIN &= ~RTCAE; + /* Disable alarm interrupt */ + RTCCTL01 &= ~RTCAIE; + /* Clear Alarm Enable for both hour and min */ + RTCAHOUR &= ~RTCAE; + RTCAMIN &= ~RTCAE; } void rtca_update_dow(struct DATETIME *datetime) { - uint8_t dow; + uint8_t dow; - dow = LEAPS_SINCE_YEAR(datetime->year); + dow = LEAPS_SINCE_YEAR(datetime->year); - if ((29 == rtca_get_max_days(2, datetime->year)) && (datetime->mon < 3)) - dow--; /* if this is a leap year but before February 29 */ + if ((29 == rtca_get_max_days(2, datetime->year)) && (datetime->mon < 3)) + dow--; /* if this is a leap year but before February 29 */ - /* add day of current month */ - dow += datetime->day; + /* add day of current month */ + dow += datetime->day; - /* add this month's dow value */ - switch (datetime->mon) { - case 5: - dow += 1; - break; + /* add this month's dow value */ + switch (datetime->mon) { + case 5: + dow += 1; + break; - case 8: - dow += 2; - break; + case 8: + dow += 2; + break; - case 2: - case 3: - case 11: - dow += 3; - break; + case 2: + case 3: + case 11: + dow += 3; + break; - case 6: - dow += 4; - break; + case 6: + dow += 4; + break; - case 9: - case 12: - dow += 5; - break; + case 9: + case 12: + dow += 5; + break; - case 4: - case 7: - dow += 6; - break; - } + case 4: + case 7: + dow += 6; + break; + } - dow = dow % 7; - datetime->dow = dow; + dow = dow % 7; + datetime->dow = dow; } void rtca_set_date() { - /* Stop RTC timekeeping for a while */ - rtca_stop(); + /* Stop RTC timekeeping for a while */ + rtca_stop(); - rtca_update_dow(&rtca_time); + rtca_update_dow(&rtca_time); - /* update RTC registers and local cache */ - RTCDAY = rtca_time.day; - RTCDOW = rtca_time.dow; - RTCMON = rtca_time.mon; - RTCYEARL = rtca_time.year & 0xff; - RTCYEARH = rtca_time.year >> 8; + /* update RTC registers and local cache */ + RTCDAY = rtca_time.day; + RTCDOW = rtca_time.dow; + RTCMON = rtca_time.mon; + RTCYEARL = rtca_time.year & 0xff; + RTCYEARH = rtca_time.year >> 8; - /* Resume RTC time keeping */ - rtca_start(); + /* Resume RTC time keeping */ + rtca_start(); #ifdef CONFIG_RTC_DST - /* calculate new DST switch dates */ - rtc_dst_calculate_dates(rtca_time.year, rtca_time.mon, rtca_time.day, rtca_time.hour); + /* calculate new DST switch dates */ + rtc_dst_calculate_dates(rtca_time.year, rtca_time.mon, rtca_time.day, rtca_time.hour); #endif } __attribute__((interrupt(RTC_A_VECTOR))) void RTC_A_ISR(void) { - /* the IV is cleared after a read, so we store it */ - uint16_t iv = RTCIV; + /* the IV is cleared after a read, so we store it */ + uint16_t iv = RTCIV; - /* copy register values */ - rtca_time.sec = RTCSEC; + /* copy register values */ + rtca_time.sec = RTCSEC; - /* count system time */ - rtca_time.sys++; + /* count system time */ + rtca_time.sys++; - enum rtca_tevent ev = 0; + enum rtca_tevent ev = 0; - /* second event (from the read ready interrupt flag) */ - if (iv == RTCIV_RTCRDYIFG) { /* Did second changed */ - ev = RTCA_EV_SECOND; - goto finish; - } + /* second event (from the read ready interrupt flag) */ + if (iv == RTCIV_RTCRDYIFG) { /* Did second changed */ + ev = RTCA_EV_SECOND; + goto finish; + } - if (iv == RTCIV_RTCAIFG) { /* Did alarm event occurred */ - ev = RTCA_EV_ALARM; - goto finish; - } + if (iv == RTCIV_RTCAIFG) { /* Did alarm event occurred */ + ev = RTCA_EV_ALARM; + goto finish; + } - if (iv == RTCIV_RTCTEVIFG) /* Did minute changed */ - { - ev = RTCA_EV_MINUTE; - rtca_time.min = RTCMIN; + if (iv == RTCIV_RTCTEVIFG) /* Did minute changed */ + { + ev = RTCA_EV_MINUTE; + rtca_time.min = RTCMIN; - if (rtca_time.min != 0) /* Hour changed */ - goto finish; + if (rtca_time.min != 0) /* Hour changed */ + goto finish; - ev |= RTCA_EV_HOUR; - rtca_time.hour = RTCHOUR; + ev |= RTCA_EV_HOUR; + rtca_time.hour = RTCHOUR; #ifdef CONFIG_RTC_DST - rtc_dst_hourly_update(); + rtc_dst_hourly_update(); #endif - if (rtca_time.hour != 0) /* Day changed */ - goto finish; + if (rtca_time.hour != 0) /* Day changed */ + goto finish; - ev |= RTCA_EV_DAY; - rtca_time.day = RTCDAY; - rtca_time.dow = RTCDOW; + ev |= RTCA_EV_DAY; + rtca_time.day = RTCDAY; + rtca_time.dow = RTCDOW; - if (rtca_time.day != 1) /* Month changed */ - goto finish; + if (rtca_time.day != 1) /* Month changed */ + goto finish; - ev |= RTCA_EV_MONTH; - rtca_time.mon = RTCMON; + ev |= RTCA_EV_MONTH; + rtca_time.mon = RTCMON; - if (rtca_time.mon != 1) /* Year changed */ - goto finish; + if (rtca_time.mon != 1) /* Year changed */ + goto finish; - ev |= RTCA_EV_YEAR; - rtca_time.year = RTCYEARL | (RTCYEARH << 8); + ev |= RTCA_EV_YEAR; + rtca_time.year = RTCYEARL | (RTCYEARH << 8); #ifdef CONFIG_RTC_DST - /* calculate new DST switch dates */ - rtc_dst_calculate_dates(rtca_time.year, rtca_time.mon, rtca_time.day, rtca_time.hour); + /* calculate new DST switch dates */ + rtc_dst_calculate_dates(rtca_time.year, rtca_time.mon, rtca_time.day, rtca_time.hour); #endif - } + } finish: - /* append events, since ISR could be triggered - multipe times until rtca_last_event gets parsed */ - rtca_last_event |= ev; + /* append events, since ISR could be triggered + multipe times until rtca_last_event gets parsed */ + rtca_last_event |= ev; - /* exit from LPM3, give execution back to mainloop */ - _BIC_SR_IRQ(LPM3_bits); + /* exit from LPM3, give execution back to mainloop */ + _BIC_SR_IRQ(LPM3_bits); } diff --git a/drivers/rtca.h b/drivers/rtca.h index b2c1900..e620b14 100644 --- a/drivers/rtca.h +++ b/drivers/rtca.h @@ -1,25 +1,25 @@ /** - rtca.h: TI CC430 Hardware Realtime Clock (RTC_A) + rtca.h: TI CC430 Hardware Realtime Clock (RTC_A) - Copyright (C) 2011-2012 Angelo Arrifano - Copyright (C) 2016 Benjamin Sølberg + Copyright (C) 2011-2012 Angelo Arrifano + Copyright (C) 2016 Benjamin Sølberg - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ #ifndef __RTCA_H__ @@ -28,30 +28,30 @@ #include "openchronos.h" enum rtca_tevent { - RTCA_EV_NONE = 0, - RTCA_EV_ALARM = BIT0, - RTCA_EV_SECOND = BIT1, - RTCA_EV_MINUTE = BIT2, - RTCA_EV_HOUR = BIT3, - RTCA_EV_DAY = BIT4, - RTCA_EV_MONTH = BIT5, - RTCA_EV_YEAR = BIT6 + RTCA_EV_NONE = 0, + RTCA_EV_ALARM = BIT0, + RTCA_EV_SECOND = BIT1, + RTCA_EV_MINUTE = BIT2, + RTCA_EV_HOUR = BIT3, + RTCA_EV_DAY = BIT4, + RTCA_EV_MONTH = BIT5, + RTCA_EV_YEAR = BIT6 }; /* Day of week strings */ static char const * const rtca_dow_str[] = { - "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" + "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" }; struct DATETIME { - uint32_t sys; /* system time: number of seconds since power on */ - uint16_t year; /* cache of RTC year register */ - uint8_t mon; /* cache of RTC month register */ - uint8_t day; /* cache of RTC day register */ - uint8_t dow; /* cache of RTC day of week register */ - uint8_t hour; /* cache of RTC hour register */ - uint8_t min; /* cache of RTC minutes register */ - uint8_t sec; /* cache of RTC seconds register */ + uint32_t sys; /* system time: number of seconds since power on */ + uint16_t year; /* cache of RTC year register */ + uint8_t mon; /* cache of RTC month register */ + uint8_t day; /* cache of RTC day register */ + uint8_t dow; /* cache of RTC day of week register */ + uint8_t hour; /* cache of RTC hour register */ + uint8_t min; /* cache of RTC minutes register */ + uint8_t sec; /* cache of RTC seconds register */ }; struct DATETIME rtca_time; @@ -63,7 +63,7 @@ uint8_t display_am_pm; #define rtca_start() (RTCCTL01 &= ~RTCHOLD) /* the ev variable holds the time event, see enum rtca_tevent for more info. -please add -fshort-enums to CFLAGS to store rtca_tevent as only a byte */ + please add -fshort-enums to CFLAGS to store rtca_tevent as only a byte */ void rtca_init(void); uint8_t rtca_get_max_days(uint8_t month, uint16_t year); diff --git a/drivers/temperature.c b/drivers/temperature.c index fb88acc..2f622f7 100644 --- a/drivers/temperature.c +++ b/drivers/temperature.c @@ -1,58 +1,58 @@ /** - temperature.c: Temperature driver + temperature.c: Temperature driver - Copyright (C) 2012 Angelo Arrifano - Copyright (C) 2012 Matthew Excell + Copyright (C) 2012 Angelo Arrifano + Copyright (C) 2012 Matthew Excell - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ /* - Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ - - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the - distribution. - - Neither the name of Texas Instruments Incorporated nor the names of - its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ + + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the + distribution. + + Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* driver */ @@ -70,55 +70,55 @@ static uint8_t adcresult_idx = 0; void temperature_init(void) { - temperature.value = adc12_single_conversion(REFVSEL_0, - ADC12SHT0_8, ADC12INCH_10); - temperature.offset = CONFIG_TEMPERATURE_OFFSET; - - adcresult[0] = temperature.value; - adcresult[1] = temperature.value; - adcresult[2] = temperature.value; - adcresult[3] = temperature.value; + temperature.value = adc12_single_conversion(REFVSEL_0, + ADC12SHT0_8, ADC12INCH_10); + temperature.offset = CONFIG_TEMPERATURE_OFFSET; + + adcresult[0] = temperature.value; + adcresult[1] = temperature.value; + adcresult[2] = temperature.value; + adcresult[3] = temperature.value; } void temperature_measurement(void) { - /* Convert internal temperature diode voltage */ - adcresult[adcresult_idx++] = adc12_single_conversion(REFVSEL_0, - ADC12SHT0_8, ADC12INCH_10); - if (adcresult_idx == TEMPORAL_FILTER_WINDOW) - adcresult_idx = 0; - - /* Calculate temporal mean value */ - temperature.value = (temperature.value & 0xff00) - | (((uint16_t)adcresult[0] + (uint16_t)adcresult[1] - + (uint16_t)adcresult[2] + (uint16_t)adcresult[3]) >> 2); + /* Convert internal temperature diode voltage */ + adcresult[adcresult_idx++] = adc12_single_conversion(REFVSEL_0, + ADC12SHT0_8, ADC12INCH_10); + if (adcresult_idx == TEMPORAL_FILTER_WINDOW) + adcresult_idx = 0; + + /* Calculate temporal mean value */ + temperature.value = (temperature.value & 0xff00) + | (((uint16_t)adcresult[0] + (uint16_t)adcresult[1] + + (uint16_t)adcresult[2] + (uint16_t)adcresult[3]) >> 2); } void temperature_get_C(int16_t *temp) { - /* from page 67, slas554f.pdf: - ((A10/4096*1500mV) - 680mV)*(1/2.25mV) - = (A10/4096*667) - 302 - = (A10 - 1855) * (667 / 4096) */ - *temp = (((int32_t)temperature.value + temperature.offset - 1855) - * 667 * 10) / 4096; + /* from page 67, slas554f.pdf: + ((A10/4096*1500mV) - 680mV)*(1/2.25mV) + = (A10/4096*667) - 302 + = (A10 - 1855) * (667 / 4096) */ + *temp = (((int32_t)temperature.value + temperature.offset - 1855) + * 667 * 10) / 4096; } void temperature_get_F(int16_t *temp) { - /* from page 67 (slas554f.pdf): - offset: - 680mV is 0C with 2.25mV/C - if 0F is -17.78C then 0F = (680-17.78*2.25) = 640mV - scale: - if 2.25mV/C then 2.25*(5/9)=1.25mV/F - - ((A10/4096*1500mV) - 640mV)*(1/1.25mV) = - = (A10/4096*1200) - 512 - = (A10 - 1748) * (1200 / 4096) */ - *temp = (((int32_t)temperature.value + temperature.offset - 1748) - * 1200 * 10) / 4096; + /* from page 67 (slas554f.pdf): + offset: + 680mV is 0C with 2.25mV/C + if 0F is -17.78C then 0F = (680-17.78*2.25) = 640mV + scale: + if 2.25mV/C then 2.25*(5/9)=1.25mV/F + + ((A10/4096*1500mV) - 640mV)*(1/1.25mV) = + = (A10/4096*1200) - 512 + = (A10 - 1748) * (1200 / 4096) */ + *temp = (((int32_t)temperature.value + temperature.offset - 1748) + * 1200 * 10) / 4096; } diff --git a/drivers/temperature.h b/drivers/temperature.h index 17aefab..f839218 100644 --- a/drivers/temperature.h +++ b/drivers/temperature.h @@ -1,25 +1,25 @@ /** - temperature.h: Temperature driver + temperature.h: Temperature driver - Copyright (C) 2012 Angelo Arrifano - Copyright (C) 2012 Matthew Excell + Copyright (C) 2012 Angelo Arrifano + Copyright (C) 2012 Matthew Excell - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ #ifndef __TEMPERATURE_H__ @@ -33,8 +33,8 @@ void temperature_get_C(int16_t *temp); void temperature_get_F(int16_t *temp); struct { - uint16_t value; - int16_t offset; + uint16_t value; + int16_t offset; } temperature; #endif /* __TEMPERATURE_H__ */ diff --git a/drivers/timer.c b/drivers/timer.c index eaf17f8..8e1c152 100644 --- a/drivers/timer.c +++ b/drivers/timer.c @@ -1,25 +1,25 @@ /** - drivers/timer.c: Openchronos TA0 timer driver + drivers/timer.c: Openchronos TA0 timer driver - Copyright (C) 2012 Angelo Arrifano - Copyright (C) 2016-2017 Benjamin Sølberg + Copyright (C) 2012 Angelo Arrifano + Copyright (C) 2016-2017 Benjamin Sølberg - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ /* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ @@ -29,17 +29,17 @@ modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the - distribution. + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the + distribution. - Neither the name of Texas Instruments Incorporated nor the names of - its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. + Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -60,20 +60,20 @@ #include "lpm.h" /* HARDWARE TIMER ASSIGNMENT: - TA0CCR0: 20Hz timer used by the button driver - TA0CCR1: Unused - TA0CCR2: delay timer with callback - TA0CCR3: programmable timer via messagebus - TA0CCR4: timer0_delay, will enter LPMx to save power - OVERFLOW: 0.244Hz timer ~ 4.1S via messagebus - */ + TA0CCR0: 20Hz timer used by the button driver + TA0CCR1: Unused + TA0CCR2: delay timer with callback + TA0CCR3: programmable timer via messagebus + TA0CCR4: timer0_delay, will enter LPMx to save power + OVERFLOW: 0.244Hz timer ~ 4.1S via messagebus +*/ /* source is ACLK=32768Hz (nominal) with /2 divider */ #define TIMER0_FREQ 16384 /* converts microseconds to clock ticks */ #define TIMER0_TICKS_FROM_MS(T) ((((uint32_t)TIMER0_FREQ) * (uint32_t)T) \ - / ((uint32_t)1000)) + / ((uint32_t)1000)) static volatile uint8_t delay_finished; @@ -86,15 +86,15 @@ void init_timer0_20hz(); void timer0_init(void) { #ifdef CONFIG_TIMER_4S_IRQ - /* Enable overflow interrupts */ - TA0CTL |= TAIE; + /* Enable overflow interrupts */ + TA0CTL |= TAIE; #endif - /* select external 32kHz source, /2 divider, continuous mode */ - TA0CTL |= TASSEL__ACLK | ID__2 | MC__CONTINUOUS; - /* SLAU259 page 399: clear internal divider counts after setting mode, clock and divisor*/ - TA0CTL |= TACLR; - init_timer0_20hz(); + /* select external 32kHz source, /2 divider, continuous mode */ + TA0CTL |= TASSEL__ACLK | ID__2 | MC__CONTINUOUS; + /* SLAU259 page 399: clear internal divider counts after setting mode, clock and divisor*/ + TA0CTL |= TACLR; + init_timer0_20hz(); } /* ----------------------------------------------------------------------------------------------------- */ @@ -109,29 +109,29 @@ static uint16_t timer0_20hz_ticks; /* Initialize the 20Hz timer ticks */ void init_timer0_20hz() { - timer0_20hz_ticks = TIMER0_TICKS_FROM_MS(50); + timer0_20hz_ticks = TIMER0_TICKS_FROM_MS(50); } void start_timer0_20hz() { - uint16_t int_state; - ENTER_CRITICAL_SECTION(int_state); - if (ref_count_20hz == 0) { - /*50ms from generate compare interrupt*/ - TA0CCR0 = TA0R + timer0_20hz_ticks; - TA0CCTL0 |= CCIE; // Enable timer0 20hz interrupt - } - ref_count_20hz++; - EXIT_CRITICAL_SECTION(int_state); + uint16_t int_state; + ENTER_CRITICAL_SECTION(int_state); + if (ref_count_20hz == 0) { + /*50ms from generate compare interrupt*/ + TA0CCR0 = TA0R + timer0_20hz_ticks; + TA0CCTL0 |= CCIE; // Enable timer0 20hz interrupt + } + ref_count_20hz++; + EXIT_CRITICAL_SECTION(int_state); } void stop_timer0_20hz() { - uint16_t int_state; - ENTER_CRITICAL_SECTION(int_state); - ref_count_20hz--; - if (ref_count_20hz == 0) { - TA0CCTL0 &= ~CCIE; // Disable timer0 20hz interrupt - } - EXIT_CRITICAL_SECTION(int_state); + uint16_t int_state; + ENTER_CRITICAL_SECTION(int_state); + ref_count_20hz--; + if (ref_count_20hz == 0) { + TA0CCTL0 &= ~CCIE; // Disable timer0 20hz interrupt + } + EXIT_CRITICAL_SECTION(int_state); } /* ----------------------------- */ @@ -141,42 +141,42 @@ void stop_timer0_20hz() { /* This function was based on original Texas Instruments implementation, see LICENSE-TI for more information. */ void timer0_delay(uint16_t duration, uint16_t LPM_bits) { - delay_finished = 0; + delay_finished = 0; - /* Set next CCR match */ - TA0CCR4 = TA0R + TIMER0_TICKS_FROM_MS(duration); + /* Set next CCR match */ + TA0CCR4 = TA0R + TIMER0_TICKS_FROM_MS(duration); - /* enable interrupt */ - TA0CCTL4 |= CCIE; + /* enable interrupt */ + TA0CCTL4 |= CCIE; - /* Wait for interrupt */ - while (1) { - /* enter low power mode */ - enter_lpm_gie(LPM_bits); + /* Wait for interrupt */ + while (1) { + /* enter low power mode */ + enter_lpm_gie(LPM_bits); - // Service watchdog (reset counter) - wdt_poll(); + // Service watchdog (reset counter) + wdt_poll(); - /* The interrupt routine sets delay_finished to signal us - that a interrupt happened */ - if (delay_finished == 1) - break; - } + /* The interrupt routine sets delay_finished to signal us + that a interrupt happened */ + if (delay_finished == 1) + break; + } - /* disable interrupt */ - TA0CCTL4 &= ~CCIE; + /* disable interrupt */ + TA0CCTL4 &= ~CCIE; } void timer0_delay_callback_destroy(void) { - /* abort a delay without calling callback */ - /* disable interrupt */ - TA0CCTL2 &= ~CCIE; + /* abort a delay without calling callback */ + /* disable interrupt */ + TA0CCTL2 &= ~CCIE; - /* clear any pending interrupt? */ - TA0CCTL2 = 0; + /* clear any pending interrupt? */ + TA0CCTL2 = 0; - /* clear callback */ - delay_callback = NULL; + /* clear callback */ + delay_callback = NULL; } /* @@ -184,37 +184,37 @@ void timer0_delay_callback_destroy(void) { * context and that LPM state isn't changed after execution */ void timer0_delay_callback(uint16_t duration, void(*cbfn)(void)) { - timer0_delay_callback_destroy(); + timer0_delay_callback_destroy(); - /* setup where to go on completion */ - delay_callback = cbfn; + /* setup where to go on completion */ + delay_callback = cbfn; - /* Set next CCR match */ - TA0CCR2 = TA0R + TIMER0_TICKS_FROM_MS(duration); + /* Set next CCR match */ + TA0CCR2 = TA0R + TIMER0_TICKS_FROM_MS(duration); - /* clear any pending interrupt? */ - TA0CCTL2 = 0; + /* clear any pending interrupt? */ + TA0CCTL2 = 0; - /* enable interrupt */ - TA0CCTL2 |= CCIE; + /* enable interrupt */ + TA0CCTL2 |= CCIE; } /* programable timer: - duration is in miliseconds, min=1, max=1000 */ + duration is in miliseconds, min=1, max=1000 */ void timer0_create_prog_timer(uint16_t duration) { - timer0_prog_ticks = TIMER0_TICKS_FROM_MS(duration); + timer0_prog_ticks = TIMER0_TICKS_FROM_MS(duration); - /* set timer to start as soon as possible */ - TA0CCR3 = TA0R + timer0_prog_ticks; + /* set timer to start as soon as possible */ + TA0CCR3 = TA0R + timer0_prog_ticks; - /* enable timer */ - TA0CCTL3 |= CCIE; + /* enable timer */ + TA0CCTL3 |= CCIE; } void timer0_destroy_prog_timer() { - /* disable timer */ - TA0CCTL3 &= ~CCIE; + /* disable timer */ + TA0CCTL3 &= ~CCIE; } /* ------------------------ */ @@ -224,75 +224,75 @@ void timer0_destroy_prog_timer() { /* interrupt vector for CCR0 */ __attribute__((interrupt(TIMER0_A0_VECTOR))) void timer0_A0_ISR(void) { - /* setup timer for next time */ - TA0CCR0 = TA0R + timer0_20hz_ticks; + /* setup timer for next time */ + TA0CCR0 = TA0R + timer0_20hz_ticks; - /* increase 20hz counter */ - timer0_20hz_counter++; + /* increase 20hz counter */ + timer0_20hz_counter++; - /* store 20hz timer event */ - timer0_last_event |= TIMER0_EVENT_20HZ; + /* store 20hz timer event */ + timer0_last_event |= TIMER0_EVENT_20HZ; - /* exit from LPM3, give execution back to mainloop */ - _BIC_SR_IRQ(LPM3_bits); + /* exit from LPM3, give execution back to mainloop */ + _BIC_SR_IRQ(LPM3_bits); } /* interrupt vector for CCR1-4 and overflow */ __attribute__((interrupt(TIMER0_A1_VECTOR))) void timer0_A1_ISR(void) { - /* reading TA0IV automatically resets the interrupt flag */ - uint8_t flag = (uint8_t) TA0IV; // ISR reason. Only look at the lower 8 bits - - /* programable timer */ - if (flag == TA0IV_TA0CCR3) { - /* setup timer for next time */ - TA0CCR3 = TA0R + timer0_prog_ticks; - - /* store event */ - timer0_last_event |= TIMER0_EVENT_PROG; - - goto exit_lpm3; - } - - /* delay timer */ - if (flag == TA0IV_TA0CCR4) { - delay_finished = 1; - goto exit_lpm3; - } - - /* one-shot delay timer with callback */ - if (flag == TA0IV_TA0CCR2) { - /* disable interrupt */ - TA0CCTL2 &= ~CCIE; - - /* maybe call vector */ - if (delay_callback) { - void (*tmpfn)(void) = delay_callback; - /* reset timer so it's not called again */ - delay_callback = NULL; - /* but then it may be re-set by callback fn */ - tmpfn(); - } - - /* return to LPMx (don't mess with SR bits) */ - return; - } + /* reading TA0IV automatically resets the interrupt flag */ + uint8_t flag = (uint8_t) TA0IV; // ISR reason. Only look at the lower 8 bits + + /* programable timer */ + if (flag == TA0IV_TA0CCR3) { + /* setup timer for next time */ + TA0CCR3 = TA0R + timer0_prog_ticks; + + /* store event */ + timer0_last_event |= TIMER0_EVENT_PROG; + + goto exit_lpm3; + } + + /* delay timer */ + if (flag == TA0IV_TA0CCR4) { + delay_finished = 1; + goto exit_lpm3; + } + + /* one-shot delay timer with callback */ + if (flag == TA0IV_TA0CCR2) { + /* disable interrupt */ + TA0CCTL2 &= ~CCIE; + + /* maybe call vector */ + if (delay_callback) { + void (*tmpfn)(void) = delay_callback; + /* reset timer so it's not called again */ + delay_callback = NULL; + /* but then it may be re-set by callback fn */ + tmpfn(); + } + + /* return to LPMx (don't mess with SR bits) */ + return; + } #ifdef CONFIG_TIMER_4S_IRQ - /* 0.24Hz timer, ticked by overflow interrupts */ - if (flag == TA0IV_TA0IFG) { - /* store event */ - timer0_last_event |= TIMER0_EVENT_4S; + /* 0.24Hz timer, ticked by overflow interrupts */ + if (flag == TA0IV_TA0IFG) { + /* store event */ + timer0_last_event |= TIMER0_EVENT_4S; - goto exit_lpm3; - } + goto exit_lpm3; + } #endif - return; + return; exit_lpm3: - /* exit from LPM3, give execution back to mainloop */ - _BIC_SR_IRQ(LPM3_bits); + /* exit from LPM3, give execution back to mainloop */ + _BIC_SR_IRQ(LPM3_bits); } diff --git a/drivers/timer.h b/drivers/timer.h index 374c799..f3f3472 100644 --- a/drivers/timer.h +++ b/drivers/timer.h @@ -1,32 +1,32 @@ /** - drivers/timer.h: Openchronos TA0 timer driver + drivers/timer.h: Openchronos TA0 timer driver - Copyright (C) 2012 Angelo Arrifano - Copyright (C) 2016 Benjamin Sølberg + Copyright (C) 2012 Angelo Arrifano + Copyright (C) 2016 Benjamin Sølberg - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ /*! - \file timer.h - \brief openchronos-ng timer driver - \details This driver takes care of the Timer0 hardware timer. From this hardware timer the driver produces two hardware-based timers running at 20Hz and 4s (period). The events produced by those timers are available in #sys_message. Beyound the fixed frequency timers, this driver also implements a programmable timer and a programmable delay. - \note If you are looking to timer events, then see #sys_message + \file timer.h + \brief openchronos-ng timer driver + \details This driver takes care of the Timer0 hardware timer. From this hardware timer the driver produces two hardware-based timers running at 20Hz and 4s (period). The events produced by those timers are available in #sys_message. Beyound the fixed frequency timers, this driver also implements a programmable timer and a programmable delay. + \note If you are looking to timer events, then see #sys_message */ #include "openchronos.h" @@ -38,82 +38,82 @@ void start_timer0_20hz(); void stop_timer0_20hz(); /*! - \brief Initializes the timer - \details This functions is called once upon system initialization. - \note Modules are strictly forbidden to call this function. - \internal + \brief Initializes the timer + \details This functions is called once upon system initialization. + \note Modules are strictly forbidden to call this function. + \internal */ void timer0_init(void); /*! - \brief 20Hz counter. - \details This is a counter variable, its value is updated at 20Hz. You can use this to measure timings. - \note counter overflows should be relatively safe since they only happen once each 3276.8 seconds. However you should handle overflows if your application cannot accept sporadic failures in measurement. + \brief 20Hz counter. + \details This is a counter variable, its value is updated at 20Hz. You can use this to measure timings. + \note counter overflows should be relatively safe since they only happen once each 3276.8 seconds. However you should handle overflows if your application cannot accept sporadic failures in measurement. */ volatile uint16_t timer0_20hz_counter; /*! - \brief creates a 1000Hz - 1Hz programmable timer - \details Creates a timer programmable from 1Hz up to 1000Hz. The timer event is available in #sys_message. - \note You should check what modules are using this function because it cannot be used by more than one module at same time. We recommend you use one of the available fixed timers. If you really need another ticking frequency, contact the openchronos-ng developers for a better solution. - \sa timer0_destroy_prog_timer + \brief creates a 1000Hz - 1Hz programmable timer + \details Creates a timer programmable from 1Hz up to 1000Hz. The timer event is available in #sys_message. + \note You should check what modules are using this function because it cannot be used by more than one module at same time. We recommend you use one of the available fixed timers. If you really need another ticking frequency, contact the openchronos-ng developers for a better solution. + \sa timer0_destroy_prog_timer */ void timer0_create_prog_timer( - uint16_t duration /*!< timer period between 1 and 1000 milliseconds. */ -); + uint16_t duration /*!< timer period between 1 and 1000 milliseconds. */ + ); /*! - \brief destroys a running programmable timer - \sa timer0_create_prog_timer + \brief destroys a running programmable timer + \sa timer0_create_prog_timer */ void timer0_destroy_prog_timer(); /*! - \brief 1ms - 1s programmable delay - \details delays execution for \b duration milliseconds. During the delay, interrupts are still generated but #sys_message only broadcasts the events after the delay has finished. - The second argument is put directly into the _STATUS_ register. This could of course disrupt the state of the watch. Please be careful and take a look at http://mspgcc.sourceforge.net/manual/x1028.html for information regarding the _STATUS_ register. - \note Please avoid using this. No processing is done in the background during the delay, which can have impact in modules that require a responsive system. + \brief 1ms - 1s programmable delay + \details delays execution for \b duration milliseconds. During the delay, interrupts are still generated but #sys_message only broadcasts the events after the delay has finished. + The second argument is put directly into the _STATUS_ register. This could of course disrupt the state of the watch. Please be careful and take a look at http://mspgcc.sourceforge.net/manual/x1028.html for information regarding the _STATUS_ register. + \note Please avoid using this. No processing is done in the background during the delay, which can have impact in modules that require a responsive system. */ void timer0_delay( - uint16_t duration, /*!< delay duration between 1 and 1000 milliseconds */ - uint16_t LPM_bits /*!< LPM bits to put in the status register, so the user can choose LPM level */ -); + uint16_t duration, /*!< delay duration between 1 and 1000 milliseconds */ + uint16_t LPM_bits /*!< LPM bits to put in the status register, so the user can choose LPM level */ + ); /*! - \brief schedule a callback after a delay - */ + \brief schedule a callback after a delay +*/ /*! - \brief 1ms - 1s programmable delay to callback - \details schedules a callback to the provided function after \b duration milliseconds. Does not suspend other interrupts. - */ + \brief 1ms - 1s programmable delay to callback + \details schedules a callback to the provided function after \b duration milliseconds. Does not suspend other interrupts. +*/ void timer0_delay_callback( - uint16_t duration, /*!< delay duration in ms */ - void(*cbfn)(void) /*!< pointer to function to call on completion */ -); + uint16_t duration, /*!< delay duration in ms */ + void(*cbfn)(void) /*!< pointer to function to call on completion */ + ); /*! - \brief abort any pending delay callback - */ + \brief abort any pending delay callback +*/ void timer0_delay_callback_destroy(void); /*! - \brief Bitfield of events produced by this driver + \brief Bitfield of events produced by this driver */ enum timer0_event { - TIMER0_EVENT_NONE = 0, /*!< EMPTY EVENT */ + TIMER0_EVENT_NONE = 0, /*!< EMPTY EVENT */ #ifdef CONFIG_TIMER_4S_IRQ - TIMER0_EVENT_4S = BIT0, /*!< 0.24Hz ~ 4.1s period event */ + TIMER0_EVENT_4S = BIT0, /*!< 0.24Hz ~ 4.1s period event */ #endif - TIMER0_EVENT_20HZ = BIT1, /*!< 20Hz event */ - TIMER0_EVENT_PROG = BIT2 /*!< programmable timer event */ + TIMER0_EVENT_20HZ = BIT1, /*!< 20Hz event */ + TIMER0_EVENT_PROG = BIT2 /*!< programmable timer event */ }; /*! - \brief Bitfield holding the last generated (timer) event. - \details Timer0 interrupt routines update this variable with the last happening events. Inside the mainloop, the system then clears this variable after reading it. Read events are broadcasted in #sys_message. - \note This function is to be used exclusively by the system. No module is allowed to read or write to this variable. - \internal + \brief Bitfield holding the last generated (timer) event. + \details Timer0 interrupt routines update this variable with the last happening events. Inside the mainloop, the system then clears this variable after reading it. Read events are broadcasted in #sys_message. + \note This function is to be used exclusively by the system. No module is allowed to read or write to this variable. + \internal */ volatile enum timer0_event timer0_last_event; diff --git a/drivers/utils.h b/drivers/utils.h index 262d911..b222114 100644 --- a/drivers/utils.h +++ b/drivers/utils.h @@ -1,30 +1,30 @@ /** - util.h: openchronos-ng messaging system + util.h: openchronos-ng messaging system - Copyright (C) 2012 Angelo Arrifano + Copyright (C) 2012 Angelo Arrifano - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ /*! - \file utils.h - \brief openchronos-ng misc utilities - \details Misc utilities + \file utils.h + \brief openchronos-ng misc utilities + \details Misc utilities */ #include "openchronos.h" diff --git a/drivers/vti_as.c b/drivers/vti_as.c index 87e8be4..45dd7ae 100644 --- a/drivers/vti_as.c +++ b/drivers/vti_as.c @@ -1,60 +1,60 @@ /** - vti_as.c: accelerometer interface + vti_as.c: accelerometer interface - Copyright (C) 2012 Paolo Di Prodi + Copyright (C) 2012 Paolo Di Prodi - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ /******************************************************************************* -// -// Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ -// -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the -// distribution. -// -// Neither the name of Texas Instruments Incorporated nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// ****************************************************************************/ + // + // Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ + // + // + // Redistribution and use in source and binary forms, with or without + // modification, are permitted provided that the following conditions + // are met: + // + // Redistributions of source code must retain the above copyright + // notice, this list of conditions and the following disclaimer. + // + // Redistributions in binary form must reproduce the above copyright + // notice, this list of conditions and the following disclaimer in the + // documentation and/or other materials provided with the + // distribution. + // + // Neither the name of Texas Instruments Incorporated nor the names of + // its contributors may be used to endorse or promote products derived + // from this software without specific prior written permission. + // + // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + // + // ****************************************************************************/ /* VTI CMA3000-D0x acceleration sensor driver functions */ /******************************************************************************/ @@ -64,19 +64,20 @@ /* system */ #include "openchronos.h" #include "vti_as.h" +#include "as.h" #include "timer.h" #ifndef CONFIG_MOD_ACCELEROMETER void as_disconnect(void) { - AS_PWR_OUT &= ~AS_PWR_PIN; /* Power off */ - AS_INT_OUT &= ~AS_INT_PIN;/* Pin to low to avoid floating pins */ - AS_SPI_OUT &= ~(AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN);/* Pin to low to avoid floating pins */ - AS_CSN_OUT &= ~AS_CSN_PIN;/* Pin to low to avoid floating pins */ - AS_INT_DIR |= AS_INT_PIN;/* Pin to output to avoid floating pins */ - AS_SPI_DIR |= AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN;/* Pin to output to avoid floating pins */ - AS_CSN_DIR |= AS_CSN_PIN;/* Pin to output to avoid floating pins */ - AS_PWR_DIR |= AS_PWR_PIN;/* Power pin to output direction */ + AS_PWR_OUT &= ~AS_PWR_PIN; /* Power off */ + AS_INT_OUT &= ~AS_INT_PIN;/* Pin to low to avoid floating pins */ + AS_SPI_OUT &= ~(AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN);/* Pin to low to avoid floating pins */ + AS_CSN_OUT &= ~AS_CSN_PIN;/* Pin to low to avoid floating pins */ + AS_INT_DIR |= AS_INT_PIN;/* Pin to output to avoid floating pins */ + AS_SPI_DIR |= AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN;/* Pin to output to avoid floating pins */ + AS_CSN_DIR |= AS_CSN_PIN;/* Pin to output to avoid floating pins */ + AS_PWR_DIR |= AS_PWR_PIN;/* Power pin to output direction */ } #else @@ -120,8 +121,6 @@ void write_MDTMR(uint8_t multiplier); /* Global Variable section */ /* olatile as_status_register_flags as_status; */ -/* Global flag for proper acceleration sensor operation */ -uint8_t as_ok; /******************************************************************************/ @@ -139,31 +138,29 @@ volatile as_status_register_flags as_status; void as_init(void) { #ifdef AS_DISCONNECT - /* Deactivate connection to acceleration sensor */ - AS_PWR_OUT &= ~AS_PWR_PIN; /* Power off */ - AS_INT_OUT &= ~AS_INT_PIN; /* Pin to low to avoid floating pins */ - AS_SPI_OUT &= ~(AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN); /* Pin to low to avoid floating pins */ - AS_CSN_OUT &= ~AS_CSN_PIN; /* Pin to low to avoid floating pins */ - AS_INT_DIR |= AS_INT_PIN; /* Pin to output to avoid floating pins */ - AS_SPI_DIR |= AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN; /* Pin to output to avoid floating pins */ - AS_CSN_DIR |= AS_CSN_PIN; /* Pin to output to avoid floating pins */ - AS_PWR_DIR |= AS_PWR_PIN; /* Power pin to output direction */ + /* Deactivate connection to acceleration sensor */ + AS_PWR_OUT &= ~AS_PWR_PIN; /* Power off */ + AS_INT_OUT &= ~AS_INT_PIN; /* Pin to low to avoid floating pins */ + AS_SPI_OUT &= ~(AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN); /* Pin to low to avoid floating pins */ + AS_CSN_OUT &= ~AS_CSN_PIN; /* Pin to low to avoid floating pins */ + AS_INT_DIR |= AS_INT_PIN; /* Pin to output to avoid floating pins */ + AS_SPI_DIR |= AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN; /* Pin to output to avoid floating pins */ + AS_CSN_DIR |= AS_CSN_PIN; /* Pin to output to avoid floating pins */ + AS_PWR_DIR |= AS_PWR_PIN; /* Power pin to output direction */ #else - AS_INT_DIR &= ~AS_INT_PIN; /* Input */ - AS_SPI_DIR &= ~AS_SDI_PIN;/* Input */ - AS_SPI_DIR |= AS_SDO_PIN + AS_SCK_PIN;/* Output */ - AS_SPI_SEL |= AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN;/* Port pins to SDO, SDI and SCK function */ - AS_CSN_OUT |= AS_CSN_PIN;/* CSN=1 */ - AS_CSN_DIR |= AS_CSN_PIN; - AS_PWR_OUT |= AS_PWR_PIN;/* VDD=1 */ - AS_PWR_DIR |= AS_PWR_PIN; + AS_INT_DIR &= ~AS_INT_PIN; /* Input */ + AS_SPI_DIR &= ~AS_SDI_PIN;/* Input */ + AS_SPI_DIR |= AS_SDO_PIN + AS_SCK_PIN;/* Output */ + AS_SPI_SEL |= AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN;/* Port pins to SDO, SDI and SCK function */ + AS_CSN_OUT |= AS_CSN_PIN;/* CSN=1 */ + AS_CSN_DIR |= AS_CSN_PIN; + AS_PWR_OUT |= AS_PWR_PIN;/* VDD=1 */ + AS_PWR_DIR |= AS_PWR_PIN; #endif - /* Reset global sensor flag */ - as_ok = 1; - /* Init configuration parameters to measurment mode */ - as_config.range = 8; - as_config.sampling = SAMPLING_100_HZ; + /* Init configuration parameters to measurment mode */ + as_config.range = 8; + as_config.sampling = SAMPLING_100_HZ; } @@ -176,94 +173,94 @@ void as_init(void) void change_mode(uint8_t mode) { - uint8_t bConfig = 0x00; - -/* Configure sensor and start to sample data */ - switch (mode) { - case FALL_MODE: - if (as_config.range == 2) { - bConfig = 0x80; - - if (as_config.sampling == SAMPLING_100_HZ) - bConfig |= 0x0A; - else if (as_config.sampling == SAMPLING_400_HZ) - bConfig |= 0x0C; - } else if (as_config.range == 8) { - bConfig = 0x00; - - if (as_config.sampling == SAMPLING_100_HZ) - bConfig |= 0x0A; - else if (as_config.sampling == SAMPLING_400_HZ) - bConfig |= 0x0C; - } - - /* fall time as long as possible 150 msec at 100 Hz */ - write_FFTMR(as_config.MDFFTMR); - /* threshold for computation */ - write_FFTHR(as_config.FFTHR); - - break; - - case MEASUREMENT_MODE: - - /* Configure sensor and start to sample data */ - if (as_config.range == 2) { - bConfig = 0x80; - - if (as_config.sampling == SAMPLING_100_HZ) - bConfig |= 0x02; - else if (as_config.sampling == SAMPLING_400_HZ) - bConfig |= 0x04; - } else if (as_config.range == 8) { - bConfig = 0x00; - - if (as_config.sampling == SAMPLING_40_HZ) - bConfig |= 0x06; - else if (as_config.sampling == SAMPLING_100_HZ) - bConfig |= 0x02; - else if (as_config.sampling == SAMPLING_400_HZ) - bConfig |= 0x04; - } - - break; - - case ACTIVITY_MODE: - - /* Configure sensor and start to sample data */ - if (as_config.range == 2) { - bConfig = 0x80; - - if (as_config.sampling == SAMPLING_10_HZ) - bConfig |= 0x08; - } else if (as_config.range == 8) { - bConfig = 0x00; - - if (as_config.sampling == SAMPLING_10_HZ) - bConfig |= 0x08; - } - - bConfig |= MDET_EXIT << 5; - /* fall time as long as possible 150 msec at 100 Hz */ - write_MDTMR(as_config.MDFFTMR); - /* check if lower than 571 mgrav */ - /* write_MDTHR(sAccel.MDTHR); */ - write_MDTHR(as_config.MDTHR); - break; - - default: - bConfig = 0x80; - break; - - } - - /* Wait 2 ms before entering modality to settle down */ - timer0_delay(2, LPM3_bits); - - /* write the configuration */ - as_write_register(ADDR_CTRL, bConfig); - - /* Wait 2 ms before entering modality to settle down */ - timer0_delay(2, LPM3_bits); + uint8_t bConfig = 0x00; + + /* Configure sensor and start to sample data */ + switch (mode) { + case FALL_MODE: + if (as_config.range == 2) { + bConfig = 0x80; + + if (as_config.sampling == SAMPLING_100_HZ) + bConfig |= 0x0A; + else if (as_config.sampling == SAMPLING_400_HZ) + bConfig |= 0x0C; + } else if (as_config.range == 8) { + bConfig = 0x00; + + if (as_config.sampling == SAMPLING_100_HZ) + bConfig |= 0x0A; + else if (as_config.sampling == SAMPLING_400_HZ) + bConfig |= 0x0C; + } + + /* fall time as long as possible 150 msec at 100 Hz */ + write_FFTMR(as_config.MDFFTMR); + /* threshold for computation */ + write_FFTHR(as_config.FFTHR); + + break; + + case MEASUREMENT_MODE: + + /* Configure sensor and start to sample data */ + if (as_config.range == 2) { + bConfig = 0x80; + + if (as_config.sampling == SAMPLING_100_HZ) + bConfig |= 0x02; + else if (as_config.sampling == SAMPLING_400_HZ) + bConfig |= 0x04; + } else if (as_config.range == 8) { + bConfig = 0x00; + + if (as_config.sampling == SAMPLING_40_HZ) + bConfig |= 0x06; + else if (as_config.sampling == SAMPLING_100_HZ) + bConfig |= 0x02; + else if (as_config.sampling == SAMPLING_400_HZ) + bConfig |= 0x04; + } + + break; + + case ACTIVITY_MODE: + + /* Configure sensor and start to sample data */ + if (as_config.range == 2) { + bConfig = 0x80; + + if (as_config.sampling == SAMPLING_10_HZ) + bConfig |= 0x08; + } else if (as_config.range == 8) { + bConfig = 0x00; + + if (as_config.sampling == SAMPLING_10_HZ) + bConfig |= 0x08; + } + + bConfig |= MDET_EXIT << 5; + /* fall time as long as possible 150 msec at 100 Hz */ + write_MDTMR(as_config.MDFFTMR); + /* check if lower than 571 mgrav */ + /* write_MDTHR(sAccel.MDTHR); */ + write_MDTHR(as_config.MDTHR); + break; + + default: + bConfig = 0x80; + break; + + } + + /* Wait 2 ms before entering modality to settle down */ + timer0_delay(2, LPM3_bits); + + /* write the configuration */ + as_write_register(ADDR_CTRL, bConfig); + + /* Wait 2 ms before entering modality to settle down */ + timer0_delay(2, LPM3_bits); } /******************************************************************************/ @@ -275,45 +272,45 @@ void change_mode(uint8_t mode) void as_start(uint8_t mode) { - /* Initialize SPI interface to acceleration sensor */ - AS_SPI_CTL0 |= UCSYNC | UCMST | UCMSB /* SPI master, 8 data bits, MSB first, */ - | UCCKPH; /* clock idle low, data output on falling edge */ - AS_SPI_CTL1 |= UCSSEL1; /* SMCLK as clock source */ - AS_SPI_BR0 = AS_BR_DIVIDER; /* Low byte of division factor for baud rate */ - AS_SPI_BR1 = 0x00; /* High byte of division factor for baud rate */ - AS_SPI_CTL1 &= ~UCSWRST; /* Start SPI hardware */ + /* Initialize SPI interface to acceleration sensor */ + AS_SPI_CTL0 |= UCSYNC | UCMST | UCMSB /* SPI master, 8 data bits, MSB first, */ + | UCCKPH; /* clock idle low, data output on falling edge */ + AS_SPI_CTL1 |= UCSSEL1; /* SMCLK as clock source */ + AS_SPI_BR0 = AS_BR_DIVIDER; /* Low byte of division factor for baud rate */ + AS_SPI_BR1 = 0x00; /* High byte of division factor for baud rate */ + AS_SPI_CTL1 &= ~UCSWRST; /* Start SPI hardware */ - /* Initialize interrupt pin for data read out from acceleration sensor */ - AS_INT_IES &= ~AS_INT_PIN; /* Interrupt on rising edge */ + /* Initialize interrupt pin for data read out from acceleration sensor */ + AS_INT_IES &= ~AS_INT_PIN; /* Interrupt on rising edge */ #ifdef AS_DISCONNECT - /* Enable interrupt */ - AS_INT_DIR &= ~AS_INT_PIN; /* Switch INT pin to input */ - AS_SPI_DIR &= ~AS_SDI_PIN; /* Switch SDI pin to input */ - AS_SPI_REN |= AS_SDI_PIN; /* Pulldown on SDI pin */ - AS_SPI_SEL |= AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN; /* Port pins to SDO, SDI and SCK function */ - AS_CSN_OUT |= AS_CSN_PIN; /* Deselect acceleration sensor */ - AS_PWR_OUT |= AS_PWR_PIN; /* Power on active high */ + /* Enable interrupt */ + AS_INT_DIR &= ~AS_INT_PIN; /* Switch INT pin to input */ + AS_SPI_DIR &= ~AS_SDI_PIN; /* Switch SDI pin to input */ + AS_SPI_REN |= AS_SDI_PIN; /* Pulldown on SDI pin */ + AS_SPI_SEL |= AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN; /* Port pins to SDO, SDI and SCK function */ + AS_CSN_OUT |= AS_CSN_PIN; /* Deselect acceleration sensor */ + AS_PWR_OUT |= AS_PWR_PIN; /* Power on active high */ #endif - /* Delay of >5ms required between switching on power and configuring sensor */ - timer0_delay(10, LPM3_bits); + /* Delay of >5ms required between switching on power and configuring sensor */ + timer0_delay(10, LPM3_bits); - /* Initialize interrupt pin for data read out from acceleration sensor */ - AS_INT_IFG &= ~AS_INT_PIN; /* Reset flag */ - AS_INT_IE |= AS_INT_PIN; /* Enable interrupt */ + /* Initialize interrupt pin for data read out from acceleration sensor */ + AS_INT_IFG &= ~AS_INT_PIN; /* Reset flag */ + AS_INT_IE |= AS_INT_PIN; /* Enable interrupt */ - /* Reset sensor */ - as_write_register(0x04, 0x02); - as_write_register(0x04, 0x0A); - as_write_register(0x04, 0x04); + /* Reset sensor */ + as_write_register(0x04, 0x02); + as_write_register(0x04, 0x0A); + as_write_register(0x04, 0x04); - /* Wait 5 ms before starting sensor output */ - timer0_delay(5, LPM3_bits); + /* Wait 5 ms before starting sensor output */ + timer0_delay(5, LPM3_bits); - /* then select modality */ - change_mode(mode); + /* then select modality */ + change_mode(mode); } @@ -325,24 +322,24 @@ void as_start(uint8_t mode) /******************************************************************************/ void as_stop(void) { - /* Disable interrupt */ - AS_INT_IE &= ~AS_INT_PIN; /* Disable interrupt */ + /* Disable interrupt */ + AS_INT_IE &= ~AS_INT_PIN; /* Disable interrupt */ #ifdef AS_DISCONNECT - /* Power-down sensor */ - AS_PWR_OUT &= ~AS_PWR_PIN; /* Power off */ - AS_INT_OUT &= ~AS_INT_PIN; /* Pin to low to avoid floating pins */ - AS_SPI_OUT &= ~(AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN); /* Pins to low to avoid floating pins */ - AS_SPI_SEL &= ~(AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN); /* Port pins to I/O function */ - AS_CSN_OUT &= ~AS_CSN_PIN; /* Pin to low to avoid floating pins */ - AS_INT_DIR |= AS_INT_PIN; /* Pin to output to avoid floating pins */ - AS_SPI_DIR |= AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN; /* Pins to output to avoid floating pins */ - AS_CSN_DIR |= AS_CSN_PIN; /* Pin to output to avoid floating pins */ + /* Power-down sensor */ + AS_PWR_OUT &= ~AS_PWR_PIN; /* Power off */ + AS_INT_OUT &= ~AS_INT_PIN; /* Pin to low to avoid floating pins */ + AS_SPI_OUT &= ~(AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN); /* Pins to low to avoid floating pins */ + AS_SPI_SEL &= ~(AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN); /* Port pins to I/O function */ + AS_CSN_OUT &= ~AS_CSN_PIN; /* Pin to low to avoid floating pins */ + AS_INT_DIR |= AS_INT_PIN; /* Pin to output to avoid floating pins */ + AS_SPI_DIR |= AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN; /* Pins to output to avoid floating pins */ + AS_CSN_DIR |= AS_CSN_PIN; /* Pin to output to avoid floating pins */ #else - /* Reset sensor -> sensor to powerdown */ - as_write_register(0x04, 0x02); - as_write_register(0x04, 0x0A); - as_write_register(0x04, 0x04); + /* Reset sensor -> sensor to powerdown */ + as_write_register(0x04, 0x02); + as_write_register(0x04, 0x0A); + as_write_register(0x04, 0x04); #endif } @@ -354,53 +351,47 @@ void as_stop(void) /******************************************************************************/ uint8_t as_read_register(uint8_t bAddress) { - uint8_t bResult; - uint16_t timeout; + uint8_t bResult; + uint16_t timeout; - /* Exit function if an error was detected previously */ - if (!as_ok) - return (0); + bAddress <<= 2; /* Address to be shifted left by 2 and RW bit to be reset */ - bAddress <<= 2; /* Address to be shifted left by 2 and RW bit to be reset */ + AS_SPI_REN &= ~AS_SDI_PIN; /* Pulldown on SDI pin not required */ + AS_CSN_OUT &= ~AS_CSN_PIN; /* Select acceleration sensor */ - AS_SPI_REN &= ~AS_SDI_PIN; /* Pulldown on SDI pin not required */ - AS_CSN_OUT &= ~AS_CSN_PIN; /* Select acceleration sensor */ + bResult = AS_RX_BUFFER; /* Read RX buffer just to clear interrupt flag */ - bResult = AS_RX_BUFFER; /* Read RX buffer just to clear interrupt flag */ + AS_TX_BUFFER = bAddress; /* Write address to TX buffer */ - AS_TX_BUFFER = bAddress; /* Write address to TX buffer */ + timeout = SPI_TIMEOUT; - timeout = SPI_TIMEOUT; + while (!(AS_IRQ_REG & AS_RX_IFG) && (--timeout > 0)) + ; /* Wait until new data was written into RX buffer */ - while (!(AS_IRQ_REG & AS_RX_IFG) && (--timeout > 0)) - ; /* Wait until new data was written into RX buffer */ + if (timeout == 0) { + return (0); + } - if (timeout == 0) { - as_ok = 0; - return (0); - } + bResult = AS_RX_BUFFER; /* Read RX buffer just to clear interrupt flag */ - bResult = AS_RX_BUFFER; /* Read RX buffer just to clear interrupt flag */ + AS_TX_BUFFER = 0; /* Write dummy data to TX buffer */ - AS_TX_BUFFER = 0; /* Write dummy data to TX buffer */ + timeout = SPI_TIMEOUT; - timeout = SPI_TIMEOUT; + while (!(AS_IRQ_REG & AS_RX_IFG) && (--timeout > 0)) + ; /* Wait until new data was written into RX buffer */ - while (!(AS_IRQ_REG & AS_RX_IFG) && (--timeout > 0)) - ; /* Wait until new data was written into RX buffer */ + if (timeout == 0) { + return (0); + } - if (timeout == 0) { - as_ok = 0; - return (0); - } + bResult = AS_RX_BUFFER; /* Read RX buffer */ - bResult = AS_RX_BUFFER; /* Read RX buffer */ + AS_CSN_OUT |= AS_CSN_PIN; /* Deselect acceleration sensor */ + AS_SPI_REN |= AS_SDI_PIN; /* Pulldown on SDI pin required again */ - AS_CSN_OUT |= AS_CSN_PIN; /* Deselect acceleration sensor */ - AS_SPI_REN |= AS_SDI_PIN; /* Pulldown on SDI pin required again */ - - /* Return new data from RX buffer */ - return bResult; + /* Return new data from RX buffer */ + return bResult; } /******************************************************************************/ @@ -412,53 +403,47 @@ uint8_t as_read_register(uint8_t bAddress) /******************************************************************************/ uint8_t as_write_register(uint8_t bAddress, uint8_t bData) { - uint8_t bResult; - uint16_t timeout; - - /* Exit function if an error was detected previously */ - if (!as_ok) - return (0); + uint8_t bResult; + uint16_t timeout; - bAddress <<= 2; /* Address to be shifted left by 1 */ - bAddress |= BIT1; /* RW bit to be set */ + bAddress <<= 2; /* Address to be shifted left by 1 */ + bAddress |= BIT1; /* RW bit to be set */ - AS_SPI_REN &= ~AS_SDI_PIN; /* Pulldown on SDI pin not required */ - AS_CSN_OUT &= ~AS_CSN_PIN; /* Select acceleration sensor */ + AS_SPI_REN &= ~AS_SDI_PIN; /* Pulldown on SDI pin not required */ + AS_CSN_OUT &= ~AS_CSN_PIN; /* Select acceleration sensor */ - bResult = AS_RX_BUFFER; /* Read RX buffer just to clear interrupt flag */ + bResult = AS_RX_BUFFER; /* Read RX buffer just to clear interrupt flag */ - AS_TX_BUFFER = bAddress; /* Write address to TX buffer */ + AS_TX_BUFFER = bAddress; /* Write address to TX buffer */ - timeout = SPI_TIMEOUT; + timeout = SPI_TIMEOUT; - while (!(AS_IRQ_REG & AS_RX_IFG) && (--timeout > 0)) - ; /* Wait until new data was written into RX buffer */ + while (!(AS_IRQ_REG & AS_RX_IFG) && (--timeout > 0)) + ; /* Wait until new data was written into RX buffer */ - if (timeout == 0) { - as_ok = 0; - return (0); - } + if (timeout == 0) { + return (0); + } - bResult = AS_RX_BUFFER; /* Read RX buffer just to clear interrupt flag */ + bResult = AS_RX_BUFFER; /* Read RX buffer just to clear interrupt flag */ - AS_TX_BUFFER = bData; /* Write data to TX buffer */ + AS_TX_BUFFER = bData; /* Write data to TX buffer */ - timeout = SPI_TIMEOUT; + timeout = SPI_TIMEOUT; - while (!(AS_IRQ_REG & AS_RX_IFG) && (--timeout > 0)) - ; /* Wait until new data was written into RX buffer */ + while (!(AS_IRQ_REG & AS_RX_IFG) && (--timeout > 0)) + ; /* Wait until new data was written into RX buffer */ - if (timeout == 0) { - as_ok = 0; - return (0); - } + if (timeout == 0) { + return (0); + } - bResult = AS_RX_BUFFER; /* Read RX buffer */ + bResult = AS_RX_BUFFER; /* Read RX buffer */ - AS_CSN_OUT |= AS_CSN_PIN; /* Deselect acceleration sensor */ - AS_SPI_REN |= AS_SDI_PIN; /* Pulldown on SDI pin required again */ + AS_CSN_OUT |= AS_CSN_PIN; /* Deselect acceleration sensor */ + AS_SPI_REN |= AS_SDI_PIN; /* Pulldown on SDI pin required again */ - return bResult; + return bResult; } /******************************************************************************/ @@ -469,51 +454,51 @@ uint8_t as_write_register(uint8_t bAddress, uint8_t bData) /******************************************************************************/ void as_get_data(uint8_t *data) { - /* Exit if sensor is not powered up */ - if ((AS_PWR_OUT & AS_PWR_PIN) != AS_PWR_PIN) - return; - - /* Store X/Y/Z acceleration data in buffer */ - *(data + 0) = as_read_register(0x06); - *(data + 1) = as_read_register(0x07); - *(data + 2) = as_read_register(0x08); + /* Exit if sensor is not powered up */ + if ((AS_PWR_OUT & AS_PWR_PIN) != AS_PWR_PIN) + return; + + /* Store X/Y/Z acceleration data in buffer */ + *(data + 0) = as_read_register(0x06); + *(data + 1) = as_read_register(0x07); + *(data + 2) = as_read_register(0x08); } uint8_t as_get_x(void) { - if ((AS_PWR_OUT & AS_PWR_PIN) != AS_PWR_PIN) - return 0; + if ((AS_PWR_OUT & AS_PWR_PIN) != AS_PWR_PIN) + return 0; - return as_read_register(0x06); + return as_read_register(0x06); } uint8_t as_get_y(void) { - if ((AS_PWR_OUT & AS_PWR_PIN) != AS_PWR_PIN) - return 0; + if ((AS_PWR_OUT & AS_PWR_PIN) != AS_PWR_PIN) + return 0; - return as_read_register(0x07); + return as_read_register(0x07); } uint8_t as_get_z(void) { - if ((AS_PWR_OUT & AS_PWR_PIN) != AS_PWR_PIN) - return 0; + if ((AS_PWR_OUT & AS_PWR_PIN) != AS_PWR_PIN) + return 0; - return as_read_register(0x08); + return as_read_register(0x08); } uint8_t as_get_status() { - volatile uint8_t status; + volatile uint8_t status; - if ((AS_PWR_OUT & AS_PWR_PIN) != AS_PWR_PIN) - return 0; + if ((AS_PWR_OUT & AS_PWR_PIN) != AS_PWR_PIN) + return 0; - status = as_read_register(ADDR_INT_STATUS); - return status; + status = as_read_register(ADDR_INT_STATUS); + return status; } @@ -521,23 +506,23 @@ uint8_t as_get_status() /* Default value is 8h=1000 that amounts to 143 mg at 400 Hz and 2g range */ void write_MDTHR(uint8_t multiplier) { - uint8_t bData = 0x00; + uint8_t bData = 0x00; - if (as_config.range == 2) { - bData = multiplier << 2; - /* for safety only takes B5-B1 */ - /* this is also the max allowed value */ - bData &= (0x3C); + if (as_config.range == 2) { + bData = multiplier << 2; + /* for safety only takes B5-B1 */ + /* this is also the max allowed value */ + bData &= (0x3C); - } else if (as_config.range == 8) { - bData = multiplier; - /* for safety only takes B5-B1 */ - bData &= (0x7F); - /* max range is 0x3C */ - } + } else if (as_config.range == 8) { + bData = multiplier; + /* for safety only takes B5-B1 */ + bData &= (0x7F); + /* max range is 0x3C */ + } - /* TODO force it to 0x39 for some tests */ - as_write_register(ADDR_MDTHR, bData); + /* TODO force it to 0x39 for some tests */ + as_write_register(ADDR_MDTHR, bData); } @@ -547,21 +532,21 @@ void write_MDTHR(uint8_t multiplier) void write_FFTHR(uint8_t multiplier) { - /* bData = 1100 will set the center bits for both cases */ - uint8_t bData = 0x0C; + /* bData = 1100 will set the center bits for both cases */ + uint8_t bData = 0x0C; - if (as_config.range == 2) { - bData = multiplier << 2; + if (as_config.range == 2) { + bData = multiplier << 2; - } else if (as_config.range == 8) { - bData = multiplier; + } else if (as_config.range == 8) { + bData = multiplier; - } + } - /* Take only the 6 LSB: 111111 */ - bData &= (0x3F); - as_write_register(ADDR_FFTHR, bData); + /* Take only the 6 LSB: 111111 */ + bData &= (0x3F); + as_write_register(ADDR_FFTHR, bData); } @@ -571,10 +556,10 @@ void write_FFTHR(uint8_t multiplier) /* B4= 100 msec */ void write_MDTMR(uint8_t multiplier) { - /* 0x50=400+100 msec=500 msec */ - /* mask the B6:B4 bits */ - uint8_t bData = (multiplier << 4) & 0x70; - as_write_register(ADDR_MDFFTMR, bData); + /* 0x50=400+100 msec=500 msec */ + /* mask the B6:B4 bits */ + uint8_t bData = (multiplier << 4) & 0x70; + as_write_register(ADDR_MDFFTMR, bData); } /* Set the FFTMR timer bits */ @@ -583,27 +568,27 @@ void write_MDTMR(uint8_t multiplier) /* 100 Hz -> 30 msec */ void write_FFTMR(uint8_t multiplier) { - uint8_t bData = multiplier; - /* The address of the register name MDFFTMR is 0Ah */ - /* Bits FFTMR [3:0] RW Initial Value 3h */ - /* FFTMRLSB[sec]=1/ODR[HZ] */ - /* ODR is the current output data rate defined by Mode bits */ - /* First conver the seconds in the register value with the bit weighting scheme */ - /* in manual page 15 of cm3000-dx */ - - /* - if (sAccel.sampling == 100) { / * in this sampling mode: 1/100 s=10 msec * / - / * min: 10 msec -> b0 max: 80+40+20+10=150 msec b2 b1 b0 * / - bData=multiplier; - } else if (sAccel.sampling == 400) { - / * in this sampling mode: 1/400 s=2.5 msec * / - / * min: 10 msec -> b0 max: 20+10+5+2.5=37.5 msec b2 b1 b0 * / - bData=multiplier; - } else return; - */ - /* Take only the 4 LSB */ - bData &= (0x0F); - as_write_register(ADDR_MDFFTMR, bData); + uint8_t bData = multiplier; + /* The address of the register name MDFFTMR is 0Ah */ + /* Bits FFTMR [3:0] RW Initial Value 3h */ + /* FFTMRLSB[sec]=1/ODR[HZ] */ + /* ODR is the current output data rate defined by Mode bits */ + /* First conver the seconds in the register value with the bit weighting scheme */ + /* in manual page 15 of cm3000-dx */ + + /* + if (sAccel.sampling == 100) { / * in this sampling mode: 1/100 s=10 msec * / + / * min: 10 msec -> b0 max: 80+40+20+10=150 msec b2 b1 b0 * / + bData=multiplier; + } else if (sAccel.sampling == 400) { + / * in this sampling mode: 1/400 s=2.5 msec * / + / * min: 10 msec -> b0 max: 20+10+5+2.5=37.5 msec b2 b1 b0 * / + bData=multiplier; + } else return; + */ + /* Take only the 4 LSB */ + bData &= (0x0F); + as_write_register(ADDR_MDFFTMR, bData); } diff --git a/drivers/vti_as.h b/drivers/vti_as.h index e0e3920..20b1cf6 100644 --- a/drivers/vti_as.h +++ b/drivers/vti_as.h @@ -1,22 +1,22 @@ /* - vti_as.h: accelerometer interface + vti_as.h: accelerometer interface - Copyright (C) 2012 Paolo Di Prodi , - Aljaž 'g5pw' Srebrnič + Copyright (C) 2012 Paolo Di Prodi , + Aljaž 'g5pw' Srebrnič - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . - */ + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ /******************************************************************************* @@ -84,53 +84,6 @@ extern void write_FFTHR(uint8_t mgrav); /******************************************************************************/ /* Defines section */ -/* Disconnect power supply for acceleration sensor when not used */ -#define AS_DISCONNECT - -/* Port and pin resource for SPI interface to acceleration sensor */ -/* SDO=MOSI=P1.6, SDI=MISO=P1.5, SCK=P1.7 */ -#define AS_SPI_IN (P1IN) -#define AS_SPI_OUT (P1OUT) -#define AS_SPI_DIR (P1DIR) -#define AS_SPI_SEL (P1SEL) -#define AS_SPI_REN (P1REN) -#define AS_SDO_PIN (BIT6) -#define AS_SDI_PIN (BIT5) -#define AS_SCK_PIN (BIT7) - -/* CSN=PJ.1 */ -#define AS_CSN_OUT (PJOUT) -#define AS_CSN_DIR (PJDIR) -#define AS_CSN_PIN (BIT1) - -#define AS_TX_BUFFER (UCA0TXBUF) -#define AS_RX_BUFFER (UCA0RXBUF) -#define AS_TX_IFG (UCTXIFG) -#define AS_RX_IFG (UCRXIFG) -#define AS_IRQ_REG (UCA0IFG) -#define AS_SPI_CTL0 (UCA0CTL0) -#define AS_SPI_CTL1 (UCA0CTL1) -#define AS_SPI_BR0 (UCA0BR0) -#define AS_SPI_BR1 (UCA0BR1) - -/* Port and pin resource for power-up of acceleration sensor, VDD=PJ.0 */ -#define AS_PWR_OUT (PJOUT) -#define AS_PWR_DIR (PJDIR) -#define AS_PWR_PIN (BIT0) - -/* Port, pin and interrupt resource for interrupt from acceleration sensor, CMA_INT=P2.5 */ -#define AS_INT_IN (P2IN) -#define AS_INT_OUT (P2OUT) -#define AS_INT_DIR (P2DIR) -#define AS_INT_IE (P2IE) -#define AS_INT_IES (P2IES) -#define AS_INT_IFG (P2IFG) -#define AS_INT_PIN (BIT5) - -/* SPI timeout to detect sensor failure */ -#define SPI_TIMEOUT (1000u) - - /* register address: */ #define ADDR_CTRL (0x02) #define ADDR_INT_STATUS (0x05) @@ -150,43 +103,41 @@ extern void write_FFTHR(uint8_t mgrav); /* Set system flags */ typedef union { - struct { - uint8_t motiondet : 2; /* MDET see AS_MOTION_STATUS */ - uint8_t falldet : 1; /* FFDET see AS_FALL_STATUS */ - uint8_t reserved : 5; /* reserved, initial value = 0h */ - } int_status; - /* Shortcut to all display flags (for reset) */ - uint8_t all_flags; + struct { + uint8_t motiondet : 2; /* MDET see AS_MOTION_STATUS */ + uint8_t falldet : 1; /* FFDET see AS_FALL_STATUS */ + uint8_t reserved : 5; /* reserved, initial value = 0h */ + } int_status; + /* Shortcut to all display flags (for reset) */ + uint8_t all_flags; } as_status_register_flags; extern volatile as_status_register_flags as_status; -volatile uint8_t as_last_interrupt; - /******************************************************************************/ /* Global Variable section */ struct As_Param { - /* configuration bits for motion and free fall */ - uint8_t MDTHR; - uint8_t MDFFTMR; - uint8_t FFTHR; - uint8_t sampling; - uint8_t range; - uint8_t mode; + /* configuration bits for motion and free fall */ + uint8_t MDTHR; + uint8_t MDFFTMR; + uint8_t FFTHR; + uint8_t sampling; + uint8_t range; + uint8_t mode; }; extern struct As_Param as_config; enum AS_MOTION_STATUS { - AS_NO_MOTION = 00, /* motion not detected */ - AS_TRIGGER_X = 01, /* motion trigger on x */ - AS_TRIGGER_Y = 10, /* motion trigger on y */ - AS_TRIGGER_Z = 11 /* motion trigger on z */ + AS_NO_MOTION = 00, /* motion not detected */ + AS_TRIGGER_X = 01, /* motion trigger on x */ + AS_TRIGGER_Y = 10, /* motion trigger on y */ + AS_TRIGGER_Z = 11 /* motion trigger on z */ }; extern enum AS_MOTION_STATUS as_motion_bits; enum AS_FALL_STATUS { - AS_NOFALL = 0, /* free fall not detected */ - AS_FALL /* free fall detected */ + AS_NOFALL = 0, /* free fall not detected */ + AS_FALL /* free fall detected */ }; extern enum AS_FALL_STATUS as_fall_bit; diff --git a/drivers/vti_ps.c b/drivers/vti_ps.c deleted file mode 100644 index 94feec8..0000000 --- a/drivers/vti_ps.c +++ /dev/null @@ -1,721 +0,0 @@ -// ************************************************************************************************* -// -// Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ -// -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the -// distribution. -// -// Neither the name of Texas Instruments Incorporated nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// ************************************************************************************************* -// VTI SCP1000-D0x pressure sensor driver functions -// ************************************************************************************************* - - -// ************************************************************************************************* -// Include section - -// system -#include "openchronos.h" - -// driver -#include "vti_ps.h" -//#include "timer.h" - -//TODO: see what we should do with tis -#define CONFIG_FIXEDPOINT_MATH - -#ifdef CONFIG_FIXEDPOINT_MATH -#include "dsp.h" -#endif - - -// ************************************************************************************************* -// Prototypes section -uint16_t ps_read_register(uint8_t address, uint8_t mode); -uint8_t ps_write_register(uint8_t address, uint8_t data); -uint8_t ps_twi_read(uint8_t ack); -void twi_delay(void); - - -// ************************************************************************************************* -// Defines section - - -// ************************************************************************************************* -// Global Variable section - -#ifndef CONFIG_FIXEDPOINT_MATH -// VTI pressure (hPa) to altitude (m) conversion tables -const int16_t h0[17] = { -153, 0, 111, 540, 989, 1457, 1949, 2466, 3012, 3591, 4206, 4865, 5574, 6344, 7185, 8117, 9164 }; -const uint16_t p0[17] = { 1031, 1013, 1000, 950, 900, 850, 800, 750, 700, 650, 600, 550, 500, 450, 400, 350, 300 }; -float p[17]; -#else -// Storage for pressure to altitude conversions -static int16_t pLast; // Last measured pressure in 4Pa units -static int16_t pRef; // Reference pressure at sea level in 4Pa units -static int16_t hLast; // Last altitude estimate in normalized units b/H0/2^15 -#endif - - -// Global flag for proper pressure sensor operation -uint8_t ps_ok; - - -// ************************************************************************************************* -// Extern section - - - -// ************************************************************************************************* -// @fn ps_init -// @brief Init pressure sensor I/O -// @param none -// @return none -// ************************************************************************************************* -void ps_init(void) -{ - volatile uint8_t status, eeprom; - __attribute__((unused)) volatile uint8_t success; - - PS_INT_DIR &= ~PS_INT_PIN; // DRDY is input - PS_INT_IES &= ~PS_INT_PIN; // Interrupt on DRDY rising edge - PS_TWI_OUT |= PS_SCL_PIN + PS_SDA_PIN; // SCL and SDA are outputs by default - PS_TWI_DIR |= PS_SCL_PIN + PS_SDA_PIN; // SCL and SDA are outputs by default - - // Reset global ps_ok flag - ps_ok = 0; - - // 100msec delay to allow VDD stabilisation - //Timer0_A4_Delay(CONV_MS_TO_TICKS(100)); - - // Reset pressure sensor -> powerdown sensor - success = ps_write_register(0x06, 0x01); - - // 100msec delay - //Timer0_A4_Delay(CONV_MS_TO_TICKS(100)); - - // Check if STATUS register BIT0 is cleared - status = ps_read_register(0x07, PS_TWI_8BIT_ACCESS); - - if (((status & BIT0) == 0) && (status != 0)) { - // Check EEPROM checksum in DATARD8 register - eeprom = ps_read_register(0x7F, PS_TWI_8BIT_ACCESS); - - if (eeprom == 0x01) ps_ok = 1; - else ps_ok = 0; - } -} - - -// ************************************************************************************************* -// @fn ps_start -// @brief Init pressure sensor registers and start sampling -// @param none -// @return uint8_t 1=Sensor started, 0=Sensor did not start -// ************************************************************************************************* -void ps_start(void) -{ - // Start sampling data in ultra low power mode - ps_write_register(0x03, 0x0B); -} - - - -// ************************************************************************************************* -// @fn ps_stop -// @brief Power down pressure sensor -// @param none -// @return none -// ************************************************************************************************* -void ps_stop(void) -{ - // Put sensor to standby - ps_write_register(0x03, 0x00); -} - - - -// ************************************************************************************************* -// @fn ps_twi_sda -// @brief Control SDA line -// @param uint8_t condition PS_TWI_SEND_START, PS_TWI_SEND_RESTART, PS_TWI_SEND_STOP -// PS_TWI_CHECK_ACK -// @return uint8_t 1=ACK, 0=NACK -// ************************************************************************************************* -uint8_t ps_twi_sda(uint8_t condition) -{ - uint8_t sda = 0; - - if (condition == PS_TWI_SEND_START) { - PS_TWI_SDA_OUT; // SDA is output - PS_TWI_SCL_HI; - twi_delay(); - PS_TWI_SDA_LO; - twi_delay(); - PS_TWI_SCL_LO; // SCL 1-0 transition while SDA=0 - twi_delay(); - } else if (condition == PS_TWI_SEND_RESTART) { - PS_TWI_SDA_OUT; // SDA is output - PS_TWI_SCL_LO; - PS_TWI_SDA_HI; - twi_delay(); - PS_TWI_SCL_HI; - twi_delay(); - PS_TWI_SDA_LO; - twi_delay(); - PS_TWI_SCL_LO; - twi_delay(); - } else if (condition == PS_TWI_SEND_STOP) { - PS_TWI_SDA_OUT; // SDA is output - PS_TWI_SDA_LO; - twi_delay(); - PS_TWI_SCL_LO; - twi_delay(); - PS_TWI_SCL_HI; - twi_delay(); - PS_TWI_SDA_HI; // SDA 0-1 transition while SCL=1 - twi_delay(); - } else if (condition == PS_TWI_CHECK_ACK) { - PS_TWI_SDA_IN; // SDA is input - PS_TWI_SCL_LO; - twi_delay(); - PS_TWI_SCL_HI; - twi_delay(); - sda = PS_TWI_IN & PS_SDA_PIN; - PS_TWI_SCL_LO; - } - - // Return value will only be evaluated when checking device ACK - return (sda == 0); -} - - - -// ************************************************************************************************* -// @fn twi_delay -// @brief Delay between TWI signal edges. -// @param none -// @return none -// ************************************************************************************************* -void twi_delay(void) -{ - asm(" nop"); -} - - -// ************************************************************************************************* -// @fn ps_twi_write -// @brief Clock out bits through SDA. -// @param uint8_t data Byte to send -// @return none -// ************************************************************************************************* -void ps_twi_write(uint8_t data) -{ - uint8_t i, mask; - - // Set mask byte to 10000000b - mask = BIT0 << 7; - - PS_TWI_SDA_OUT; // SDA is output - - for (i = 8; i > 0; i--) { - PS_TWI_SCL_LO; // SCL=0 - - if ((data & mask) == mask) { - PS_TWI_SDA_HI; // SDA=1 - } else { - PS_TWI_SDA_LO; // SDA=0 - } - - mask = mask >> 1; - twi_delay(); - PS_TWI_SCL_HI; // SCL=1 - twi_delay(); - } - - PS_TWI_SCL_LO; // SCL=0 - PS_TWI_SDA_IN; // SDA is input -} - - -// ************************************************************************************************* -// @fn ps_twi_read -// @brief Read bits from SDA -// @param uint8_t ack 1=Send ACK after read, 0=Send NACK after read -// @return uint8_t Bits read -// ************************************************************************************************* -uint8_t ps_twi_read(uint8_t ack) -{ - uint8_t i; - uint8_t data = 0; - - PS_TWI_SDA_IN; // SDA is input - - for (i = 0; i < 8; i++) { - PS_TWI_SCL_LO; // SCL=0 - twi_delay(); - PS_TWI_SCL_HI; // SCL=0 - twi_delay(); - - // Shift captured bits to left - data = data << 1; - - // Capture new bit - if ((PS_TWI_IN & PS_SDA_PIN) == PS_SDA_PIN) data |= BIT0; - } - - PS_TWI_SDA_OUT; // SDA is output - - // 1 aditional clock phase to generate master ACK - PS_TWI_SCL_LO; // SCL=0 - - if (ack == 1) PS_TWI_SDA_LO // Send ack -> continue read - else PS_TWI_SDA_HI // Send nack -> stop read - twi_delay(); - - PS_TWI_SCL_HI; // SCL=0 - twi_delay(); - PS_TWI_SCL_LO; - - return (data); -} - - - -// ************************************************************************************************* -// @fn as_write_register -// @brief Write a byte to the pressure sensor -// @param uint8_t address Register address -// uint8_t data Data to write -// @return uint8_t -// ************************************************************************************************* -uint8_t ps_write_register(uint8_t address, uint8_t data) -{ - volatile uint8_t success; - - ps_twi_sda(PS_TWI_SEND_START); // Generate start condition - - ps_twi_write((0x11 << 1) | PS_TWI_WRITE); // Send 7bit device address 0x11 + write bit '0' - success = ps_twi_sda(PS_TWI_CHECK_ACK); // Check ACK from device - - if (!success) return (0); - - ps_twi_write(address); // Send 8bit register address - success = ps_twi_sda(PS_TWI_CHECK_ACK); // Check ACK from device - - if (!success) return (0); - - ps_twi_write(data); // Send 8bit data to register - success = ps_twi_sda(PS_TWI_CHECK_ACK); // Check ACK from device -// Slave does not send this ACK -// if (!success) return (0); - - ps_twi_sda(PS_TWI_SEND_STOP); // Generate stop condition - - return (1); -} - - -// ************************************************************************************************* -// @fn ps_read_register -// @brief Read a byte from the pressure sensor -// @param uint8_t address Register address -// uint8_t mode PS_TWI_8BIT_ACCESS, PS_TWI_16BIT_ACCESS -// @return uint16_t Register content -// ************************************************************************************************* -uint16_t ps_read_register(uint8_t address, uint8_t mode) -{ - uint8_t success; - uint16_t data = 0; - - ps_twi_sda(PS_TWI_SEND_START); // Generate start condition - - ps_twi_write((0x11 << 1) | PS_TWI_WRITE); // Send 7bit device address 0x11 + write bit '0' - success = ps_twi_sda(PS_TWI_CHECK_ACK); // Check ACK from device - - if (!success) return (0); - - ps_twi_write(address); // Send 8bit register address - success = ps_twi_sda(PS_TWI_CHECK_ACK); // Check ACK from device - - if (!success) return (0); - - ps_twi_sda(PS_TWI_SEND_RESTART); // Generate restart condition - - ps_twi_write((0x11 << 1) | PS_TWI_READ); // Send 7bit device address 0x11 + read bit '1' - success = ps_twi_sda(PS_TWI_CHECK_ACK); // Check ACK from device - - if (!success) return (0); - - if (mode == PS_TWI_16BIT_ACCESS) { - data = ps_twi_read(1) << 8; // Read MSB 8bit data from register - data |= ps_twi_read(0); // Read LSB 8bit data from register - } else { - data = ps_twi_read(0); // Read 8bit data from register - } - - ps_twi_sda(PS_TWI_SEND_STOP); // Generate stop condition - - return (data); -} - - - -// ************************************************************************************************* -// @fn ps_get_pa -// @brief Read out pressure. Format is Pa. Range is 30000 .. 120000 Pa. -// @param none -// @return uint32_t 15-bit pressure sensor value (Pa) -// ************************************************************************************************* -uint32_t ps_get_pa(void) -{ - volatile uint32_t data = 0; - - // Get 3 MSB from DATARD8 register - data = ps_read_register(0x7F, PS_TWI_8BIT_ACCESS); - data = ((data & 0x07) << 8) << 8; - - // Get 16 LSB from DATARD16 register - data |= ps_read_register(0x80, PS_TWI_16BIT_ACCESS); - - // Convert decimal value to Pa - data = (data >> 2); - - return (data); -} - - -// ************************************************************************************************* -// @fn ps_get_temp -// @brief Read out temperature. -// @param none -// @return uint16_t 13-bit temperature value in xx.x�K format -// ************************************************************************************************* -uint16_t ps_get_temp(void) -{ - volatile uint16_t data = 0; - uint16_t temp = 0; - uint8_t is_negative = 0; - uint16_t kelvin; - - // Get 13 bit from TEMPOUT register - data = ps_read_register(0x81, PS_TWI_16BIT_ACCESS); - - // Convert negative temperatures - if ((data >> 13) & 0x1) { - // Sign extend temperature - data |= 0xC000; - // Convert two's complement - data = ~data; - data += 1; - is_negative = 1; - } - - temp = data / 2; - - // Convert from �C to �K - if (is_negative) kelvin = 2732 - temp; - else kelvin = temp + 2732; - - return (kelvin); -} - -// ************************************************************************************************* -// @fn init_pressure_table -// @brief Init pressure table with constants -// @param uint32_t p Pressure (Pa) -// @return uint16_t Altitude (m) -// ************************************************************************************************* -void init_pressure_table(void) -{ -#ifndef CONFIG_FIXEDPOINT_MATH - uint8_t i; - - for (i = 0; i < 17; i++) p[i] = p0[i]; - -#else - pLast = 101325 / 4; // Last measured pressure in 4Pa units - pRef = 101325 / 4; // Reference pressure at sea level in 4Pa units - hLast = 0; -#endif -} - -#ifdef CONFIG_FIXEDPOINT_MATH -// ************************************************************************************************* -// @fn conv_altitude_to_fraction -// @brief Relative pressure deviation from reference pressure for given altitude estimate. -// @param int16_t hh Altitude estimate (in normalised units). -// @return Calculated relative pressure deviation for this altitude -// ************************************************************************************************* -int16_t conv_altitude_to_fraction(int16_t hh) -{ - /* - The fixed part of the function of altitude can be broken into tabulated ranges - and/or interpolated according to a Taylor series expansion - (1 - f) = (1 � h/H0)^b - = 1 - h*b/H0 + h^2*b*(b�1)/2/H0^2 � h^3*b8(b�1)*(b-2)/6/H0^3 + � - At low altitudes h/H0 << 1, so this series tends to converge rapidly and is - well-suited for fixed point implementation. With one or two additional terms - the series converges accurately over the range of interest so there is no need - for table interpolation. For the proposed fixed point implementation we rewrite - this expression a bit into - hh = b*h/H0 - (1 - f) = (1 � h/H0)^b - = 1 - hh*(1 � hh*(b�1)/2/b*(1 � hh*(b�2)/3/b*(... - We stick to integer multiply and shift operations. Signed int16_t values can contain - values +/�2^15 and unsigned uint16_t values 0..2^16. In C multiplication amounts to - expanding to int32_t, integer multiply and scaling back by a proper shift operation. - - Given the above equations the natural unit of hh as the first order correction is - H0/b = 8434.48m. If we accept this as a maximum +/� range we can store int16_t hh in - units of (H0/b)/2^15 = 0,26m which keeps the resolution at less than a foot. - */ - int16_t f, hf; - // f = hh*(b � 4)/5/b, correction relevant above 3.5km: - // (Could be omitted, but it is relatively little work.) - f = mult_scale16(hh, 3132); - // f = hh*(b � 3)/4/b*(1 - f), correction relevant above 1.3km: - hf = mult_scale16(hh, 7032); - f = hf - mult_scale15(hf, f); - // f = hh*(b � 2)/3/b*(1 - f), correction relevant above 300m: - hf = mult_scale16(hh, 13533); - f = hf - mult_scale15(hf, f); - // f = hh*(b � 1)/2/b*(1 - f), correction relevant above 30m: - hf = mult_scale16(hh, 26533); - f = hf - mult_scale15(hf, f); - // f = hh*(1 - f), the linear part: - f = hh - mult_scale15(hh, f); - return f; -} - -#endif // CONFIG_FIXEDPOINT_MATH - - -// ************************************************************************************************* -// @fn update_pressure_table -// @brief Calculate pressure table for reference altitude. -// Implemented straight from VTI reference code. -// @param int16_t href Reference height -// uint32_t p_meas Pressure (Pa) -// uint16_t t_meas Temperature (10*�K) -// @return none -// ************************************************************************************************* -void update_pressure_table(int16_t href, uint32_t p_meas, uint16_t t_meas) -{ -#ifndef CONFIG_FIXEDPOINT_MATH - const float Invt00 = 0.003470415; - const float coefp = 0.00006; - volatile float p_fact; - volatile float p_noll; - volatile float hnoll; - volatile float h_low = 0; - volatile float t0; - uint8_t i; - - // Typecast arguments - volatile float fl_href = href; - volatile float fl_p_meas = (float)p_meas / 100; // Convert from Pa to hPa - volatile float fl_t_meas = (float)t_meas / 10; // Convert from 10�K to 1�K - - t0 = fl_t_meas + (0.0065 * fl_href); - - hnoll = fl_href / (t0 * Invt00); - - for (i = 0; i <= 15; i++) { - if (h0[i] > hnoll) break; - - h_low = h0[i]; - } - - p_noll = (float)(hnoll - h_low) * (1 - (hnoll - (float)h0[i]) * coefp) * ((float)p0[i] - (float)p0[i - 1]) / ((float)h0[i] - h_low) + (float)p0[i - 1]; - - // Calculate multiplicator - p_fact = fl_p_meas / p_noll; - - // Apply correction factor to pressure table - for (i = 0; i <= 16; i++) { - p[i] = p0[i] * p_fact; - } - -#else - // Note: a user-provided sea-level reference pressure in mbar as used by pilots - // would be straightforward: href = 0; p_meas = (int32_t)mbar*100; - // The altitude reading will be iteratively updated. - - // Convert to 4Pa units: - pLast = (int16_t)((p_meas + 2) >> 2); - - // Convert reference altitude to normalized units: - /*if (sys.flag.use_metric_units) { // user_altitude in m - hLast = 4 * href - mult_scale16(href, 7536); - } else { // user_altitude in ft - hLast = href + mult_scale16(href, 12068); - }*/ - - int32_t f = (int32_t)0x8000 - conv_altitude_to_fraction(hLast); - // pRef = p_meas*2^15/f: - pRef = ((((int32_t)pLast << 16) + f) >> 1) / f; - // The long division is acceptable because it happens rarely. - // The term + f) is for proper rounding. - // The <<16 and >>1 operations correct for the 15bit scale of f. -#endif -} - -#ifndef CONFIG_FIXEDPOINT_MATH -// ************************************************************************************************* -// @fn conv_pa_to_meter -// @brief Convert pressure (Pa) to altitude (m) using a conversion table -// Implemented straight from VTI reference code. -// @param uint32_t p_meas Pressure (Pa) -// uint16_t t_meas Temperature (10*�K) -// @return int16_t Altitude (m) -// ************************************************************************************************* -int16_t conv_pa_to_meter(uint32_t p_meas, uint16_t t_meas) -{ - const float coef2 = 0.0007; - const float Invt00 = 0.003470415; - volatile float hnoll; - volatile float t0; - volatile float p_low; - volatile float fl_h; - volatile int16_t h; - uint8_t i; - - // Typecast arguments - volatile float fl_p_meas = (float)p_meas / 100; // Convert from Pa to hPa - volatile float fl_t_meas = (float)t_meas / 10; // Convert from 10�K to 1�K - - for (i = 0; i <= 16; i++) { - if (p[i] < fl_p_meas) break; - - p_low = p[i]; - } - - if (i == 0) { - hnoll = (float)(fl_p_meas - p[0]) / (p[1] - p[0]) * ((float)(h0[1] - h0[0])); - } else if (i < 15) { - hnoll = (float)(fl_p_meas - p_low) * (1 - (fl_p_meas - p[i]) * coef2) / (p[i] - p_low) * ((float)(h0[i] - h0[i - 1])) + h0[i - 1]; - } else if (i == 15) { - hnoll = (float)(fl_p_meas - p_low) / (p[i] - p_low) * ((float)(h0[i] - h0[i - 1])) + h0[i - 1]; - } else { // i==16 - hnoll = (float)(fl_p_meas - p[16]) / (p[16] - p[15]) * ((float)(h0[16] - h0[15])) + h0[16]; - } - - // Compensate temperature error - t0 = fl_t_meas / (1 - hnoll * Invt00 * 0.0065); - fl_h = Invt00 * t0 * hnoll; - h = (uint16_t)fl_h; - - return (h); -} -#else -// ************************************************************************************************* -// @fn conv_pressure_to_altitude -// @brief Calculates altitude from current pressure, and -// stored reference pressure at sea level and previous altitude estimate. -// Temperature info is ignored. -// @param uint32_t p_meas Pressure (Pa) -// @param uint16_t t_meas Temperature (10*�K) Ignored !!! -// @return Estimated altitude in user-selected unit (m or ft) -// (internally filtered, slightly sluggish). -// ************************************************************************************************* -int16_t conv_pa_to_altitude(uint32_t p_meas, uint16_t t_meas) -{ - /* - Assumption: fixed, linear T(h) - T = T0 � dTdh*h - with - T0 = 288.15K (15C) - dTdh = 6.5mK/m - - Basic differential equation: - dh = -(R/G)*T(H)*dp/p - Solution: - H = H0*(1 � (p/pRef)^a) - with - H0 = T0/dTdh = 44330.77m - pRef = adjustable reference pressure at sea level (h=0). - a = dTdH*R/G = 0.190263 - R = 287.052m^2/s^2/K - G = 9.80665 (at medium latitude) - - We assume T0 and the temperature profile to be fixed; the temperature reading - of the watch is not very useful since it is strongly influenced by body heat, - clothing, shelter, etc. - - Straight evaluation of h(p) requires an unattractive long division p/pRef - with pRef the adjustable reference pressure, and the Taylor expansion does - not converge very quickly. - - Evaluation of p(h) requires a more attractive multiplication by the - user-adjustable reference pressure pRef: - f =(1 � h/H0)^b - p = pRef*f - with - b = 1/a = G/(dTdH*R) = 5.255896 - In a very crude linear iteration the h value can be updated by - delta_h = �delta_p / dpdh - The slope dpdh varies by about a factor two over the range of interest, - but we can pick a fixed value on the safe side and accept that the updates - are a bit more damped at higher altitudes. - - The sensor provides 19bit absolute pressure in units of 0.25Pa, but that is more - resolution than we can easily handle in the multiplications. We store measured - pressure p, reference pressure pRef and calculated pressure as uint16_t in units of 4Pa. - - In the units chosen for p (4Pa) and for hLast (see function conv_altitude_to_fraction), - the slope dpdh is about -0.75 at sea level down to -0.375 at high altitudes. To avoid - overshoot and instabilities we assume a bigger value and accept a minor amount of - extra filtering delay at higher altitudes. The factor 1/0.75 is approximated by 1. - */ - // Scale to 4Pa units: - int16_t p = (int16_t)((p_meas + 2) >> 2); - // Predictor to speed up response to pressure changes: -// hLast -= p - pLast; // Factor of about 1/0.75 would be better. - // Store current pressure for next predictor: - pLast = p; - // Calculate pressure ratio based on guessed altitude (serious DSP work): - int16_t f = conv_altitude_to_fraction(hLast); - // Calculate pressure expected for guessed height - uint16_t pCalculated = pRef - mult_scale15(pRef, f); - // This calculation is correct within about 7Pa. - // We still have to reverse the solution with a linearly improved guess: - hLast -= p - pCalculated; - // Iteration gain factor of about 1/0.75 would result in faster convergence, - // but even the big initial jump when the altimeter is switched on converges - // in some 5 or 6 steps to about 1m accuracy. - - /*if (sys.flag.use_metric_units) {*/ - // Altitude in meters (correct within about 0.7m): - return mult_scale16(hLast, 16869); -/* } else { - // Altitude in feet (correct within 1.5ft): - return mult_scale15(hLast, 27672); - }*/ -} -#endif // CONFIG_FIXEDPOINT_MATH diff --git a/drivers/vti_ps.h b/drivers/vti_ps.h deleted file mode 100644 index f130901..0000000 --- a/drivers/vti_ps.h +++ /dev/null @@ -1,108 +0,0 @@ -// ************************************************************************************************* -// -// Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ -// -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the -// distribution. -// -// Neither the name of Texas Instruments Incorporated nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// ************************************************************************************************* - -#ifndef VTI_PS_H_ -#define VTI_PS_H_ - -// ************************************************************************************************* -// Include section - - -// ************************************************************************************************* -// Prototypes section -extern void ps_init(void); -extern void ps_start(void); -extern void ps_stop(void); -extern uint32_t ps_get_pa(void); -extern uint16_t ps_get_temp(void); - -extern void init_pressure_table(void); -extern void update_pressure_table(int16_t href, uint32_t p_meas, uint16_t t_meas); -#ifndef CONFIG_FIXEDPOINT_MATH -extern int16_t conv_pa_to_meter(uint32_t p_meas, uint16_t t_meas); -#else -extern int16_t conv_pa_to_altitude(uint32_t p_meas, uint16_t t_meas); -#endif - -// ************************************************************************************************* -// Defines section - -// Port and pin resource for TWI interface to pressure sensor -// SCL=PJ.3, SDA=PJ.2, DRDY=P2.6 -#define PS_TWI_IN (PJIN) -#define PS_TWI_OUT (PJOUT) -#define PS_TWI_DIR (PJDIR) -#define PS_TWI_REN (PJREN) -#define PS_SCL_PIN (BIT3) -#define PS_SDA_PIN (BIT2) - -// Port, pin and interrupt resource for interrupt from acceleration sensor, DRDY=P2.6 -#define PS_INT_IN (P2IN) -#define PS_INT_OUT (P2OUT) -#define PS_INT_DIR (P2DIR) -#define PS_INT_IE (P2IE) -#define PS_INT_IES (P2IES) -#define PS_INT_IFG (P2IFG) -#define PS_INT_PIN (BIT6) - -// TWI defines -#define PS_TWI_WRITE (0u) -#define PS_TWI_READ (1u) - -#define PS_TWI_SEND_START (0u) -#define PS_TWI_SEND_RESTART (1u) -#define PS_TWI_SEND_STOP (2u) -#define PS_TWI_CHECK_ACK (3u) - -#define PS_TWI_8BIT_ACCESS (0u) -#define PS_TWI_16BIT_ACCESS (1u) - -#define PS_TWI_SCL_HI { PS_TWI_OUT |= PS_SCL_PIN; } -#define PS_TWI_SCL_LO { PS_TWI_OUT &= ~PS_SCL_PIN; } -#define PS_TWI_SDA_HI { PS_TWI_OUT |= PS_SDA_PIN; } -#define PS_TWI_SDA_LO { PS_TWI_OUT &= ~PS_SDA_PIN; } -#define PS_TWI_SDA_IN { PS_TWI_OUT |= PS_SDA_PIN; PS_TWI_DIR &= ~PS_SDA_PIN; } -#define PS_TWI_SDA_OUT { PS_TWI_DIR |= PS_SDA_PIN; } - - -// ************************************************************************************************* -// Global Variable section - - -// ************************************************************************************************* -// Extern section - - -#endif /*VTI_PS_H_*/ diff --git a/drivers/wdt.c b/drivers/wdt.c index 6ce235b..9fc7f37 100644 --- a/drivers/wdt.c +++ b/drivers/wdt.c @@ -1,43 +1,43 @@ /** - drivers/wdt.c: Watchdog timer functions + drivers/wdt.c: Watchdog timer functions - Copyright (C) 2017 Benjamin Sølberg + Copyright (C) 2017 Benjamin Sølberg - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ #include "wdt.h" inline void wdt_setup() { #ifdef USE_WATCHDOG - WDTCTL = WDTPW + WDTIS__512K + WDTSSEL__ACLK; + WDTCTL = WDTPW + WDTIS__512K + WDTSSEL__ACLK; #else - wdt_stop(); + wdt_stop(); #endif } /* Stop watchdog timer */ inline void wdt_stop() { - WDTCTL = WDTPW + WDTHOLD; + WDTCTL = WDTPW + WDTHOLD; } /* service watchdog on wakeup */ inline void wdt_poll() { #ifdef USE_WATCHDOG - WDTCTL = (WDTCTL & 0xff) | WDTPW | WDTCNTCL; + WDTCTL = (WDTCTL & 0xff) | WDTPW | WDTCNTCL; #endif } diff --git a/drivers/wdt.h b/drivers/wdt.h index a9db37f..12bbf07 100644 --- a/drivers/wdt.h +++ b/drivers/wdt.h @@ -1,24 +1,24 @@ /** - drivers/wdt.c: Watchdog timer functions + drivers/wdt.c: Watchdog timer functions - Copyright (C) 2017 Benjamin Sølberg + Copyright (C) 2017 Benjamin Sølberg - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ #include "openchronos.h" diff --git a/menu.c b/menu.c index 47647ad..30ac8df 100644 --- a/menu.c +++ b/menu.c @@ -42,20 +42,20 @@ static struct menu *menu_head; /* Menu mode stuff */ static struct { - uint8_t enabled:1; /* is menu mode enabled? */ - struct menu *item; /* the currently active menu item */ - struct menu *start_item; /* the original menu item */ - uint8_t idle_count; /* number of idle polls counts */ + uint8_t enabled:1; /* is menu mode enabled? */ + struct menu *item; /* the currently active menu item */ + struct menu *start_item; /* the original menu item */ + uint8_t idle_count; /* number of idle polls counts */ } menumode; /* Menu edit mode stuff */ static struct { - uint8_t enabled:1; /* is edit mode enabled? */ - uint8_t pos:7; /* the position for selected item */ - void (* complete_fn)(void); /* call this fn when editmode exits */ - void (* cancel_fn)(void); /* call this fn when editmode is canceled */ - struct menu_editmode_item *items; /* vector of editmode items */ - uint8_t idle_count; /* number of idle polls counts */ + uint8_t enabled:1; /* is edit mode enabled? */ + uint8_t pos:7; /* the position for selected item */ + void (*complete_fn) (void); /* call this fn when editmode exits */ + void (*cancel_fn) (void); /* call this fn when editmode is canceled */ + struct menu_editmode_item *items; /* vector of editmode items */ + uint8_t idle_count; /* number of idle polls counts */ } menu_editmode; /*************************************************************************** @@ -70,39 +70,41 @@ static void editmode_handler(void) { /* STAR button exits edit mode */ if (ports_button_pressed(PORTS_BTN_STAR, 0)) { - /* deselect item */ - menu_editmode.items[menu_editmode.pos].deselect(); + /* deselect item */ + menu_editmode.items[menu_editmode.pos].deselect(); - menu_editmode.complete_fn(); - menu_editmode.enabled = 0; - menu_editmode.idle_count = 0; + menu_editmode.complete_fn(); + menu_editmode.enabled = 0; + menu_editmode.idle_count = 0; } else if (ports_button_pressed(PORTS_BTN_NUM, 0)) { - /* deselect current item */ - menu_editmode.items[menu_editmode.pos].deselect(); + /* deselect current item */ + menu_editmode.items[menu_editmode.pos].deselect(); - /* select next item */ - menu_editmode.pos++; - if (! menu_editmode.items[menu_editmode.pos].set) - menu_editmode.pos = 0; - menu_editmode.items[menu_editmode.pos].select(); - menu_editmode.idle_count = 0; + /* select next item */ + menu_editmode.pos++; + if (!menu_editmode.items[menu_editmode.pos].set) + menu_editmode.pos = 0; + menu_editmode.items[menu_editmode.pos].select(); + menu_editmode.idle_count = 0; } else if (ports_button_pressed(PORTS_BTN_UP, 0)) { - menu_editmode.items[menu_editmode.pos].set(1); - menu_editmode.idle_count = 0; + menu_editmode.items[menu_editmode.pos].set(1); + menu_editmode.idle_count = 0; } else if (ports_button_pressed(PORTS_BTN_DOWN, 0)) { - menu_editmode.items[menu_editmode.pos].set(-1); - menu_editmode.idle_count = 0; - - } else if (menu_editmode.cancel_fn && menu_editmode.idle_count >= MENU_EDITMODE_IDLE_MAX_COUNT) { - /* deselect item */ - menu_editmode.items[menu_editmode.pos].deselect(); - - menu_editmode.cancel_fn(); - menu_editmode.enabled = 0; - menu_editmode.idle_count = 0; + menu_editmode.items[menu_editmode.pos].set(-1); + menu_editmode.idle_count = 0; + + } else if (menu_editmode.cancel_fn + && menu_editmode.idle_count >= + MENU_EDITMODE_IDLE_MAX_COUNT) { + /* deselect item */ + menu_editmode.items[menu_editmode.pos].deselect(); + + menu_editmode.cancel_fn(); + menu_editmode.enabled = 0; + menu_editmode.idle_count = 0; } } @@ -130,7 +132,7 @@ static void menumode_select(void) /* activate item */ if (menumode.item->activate_fn) - menumode.item->activate_fn(); + menumode.item->activate_fn(); } void menumode_cancel(void) @@ -147,7 +149,7 @@ static void menumode_start(void) /* deactivate current menu item */ if (menumode.item->deactivate_fn) - menumode.item->deactivate_fn(); + menumode.item->deactivate_fn(); /* enable edit mode */ menumode.enabled = 1; @@ -164,14 +166,16 @@ static void menumode_start(void) display_chars(0, LCD_SEG_L2_4_0, menumode.item->name, SEG_SET); } -static void menumode_next(void) { +static void menumode_next(void) +{ menumode.idle_count = 0; menumode.item = menumode.item->next; display_clear(0, 2); display_chars(0, LCD_SEG_L2_4_0, menumode.item->name, SEG_SET); } -static void menumode_prev(void) { +static void menumode_prev(void) +{ menumode.idle_count = 0; menumode.item = menumode.item->prev; display_clear(0, 2); @@ -181,43 +185,48 @@ static void menumode_prev(void) { static void menumode_handler(void) { if (ports_button_pressed(PORTS_BTN_STAR, 0)) { - menumode_select(); + menumode_select(); } else if (ports_button_pressed(PORTS_BTN_UP, 0)) { - menumode_next(); + menumode_next(); } else if (ports_button_pressed(PORTS_BTN_DOWN, 0)) { - menumode_prev(); + menumode_prev(); } else if (menumode.idle_count >= MENUMODE_IDLE_MAX_COUNT) { - menumode_cancel(); + menumode_cancel(); } } -static void menuitem_handler(void) { +static void menuitem_handler(void) +{ if (ports_button_pressed(PORTS_BTN_LSTAR, 1)) { - if (menumode.item->lstar_btn_fn) - menumode.item->lstar_btn_fn(); + if (menumode.item->lstar_btn_fn) + menumode.item->lstar_btn_fn(); - } else if (ports_button_pressed(PORTS_BTN_STAR, !!(menumode.item->lstar_btn_fn))) { - menumode_start(); + } else + if (ports_button_pressed + (PORTS_BTN_STAR, !!(menumode.item->lstar_btn_fn))) { + menumode_start(); } else if (ports_button_pressed(PORTS_BTN_LNUM, 1)) { - if (menumode.item->lnum_btn_fn) - menumode.item->lnum_btn_fn(); + if (menumode.item->lnum_btn_fn) + menumode.item->lnum_btn_fn(); - } else if (ports_button_pressed(PORTS_BTN_NUM, !!(menumode.item->lnum_btn_fn))) { - if (menumode.item->num_btn_fn) - menumode.item->num_btn_fn(); + } else + if (ports_button_pressed + (PORTS_BTN_NUM, !!(menumode.item->lnum_btn_fn))) { + if (menumode.item->num_btn_fn) + menumode.item->num_btn_fn(); } else if (ports_button_pressed(PORTS_BTN_UP | PORTS_BTN_DOWN, 0)) { - if (menumode.item->updown_btn_fn) - menumode.item->updown_btn_fn(); + if (menumode.item->updown_btn_fn) + menumode.item->updown_btn_fn(); } else if (ports_button_pressed(PORTS_BTN_UP, 0)) { - if (menumode.item->up_btn_fn) - menumode.item->up_btn_fn(); + if (menumode.item->up_btn_fn) + menumode.item->up_btn_fn(); } else if (ports_button_pressed(PORTS_BTN_DOWN, 0)) { - if (menumode.item->down_btn_fn) - menumode.item->down_btn_fn(); + if (menumode.item->down_btn_fn) + menumode.item->down_btn_fn(); } } @@ -225,57 +234,58 @@ static void menuitem_handler(void) { /******************** Public functions ********************/ /**********************************************************/ -void menu_timeout_poll(void) { +void menu_timeout_poll(void) +{ if (menumode.enabled) { - menumode.idle_count++; + menumode.idle_count++; } else if (menu_editmode.enabled) { - menu_editmode.idle_count++; + menu_editmode.idle_count++; } } void menu_check_buttons(void) { if (menu_editmode.enabled) { - editmode_handler(); + editmode_handler(); } else if (menumode.enabled) { - menumode_handler(); + menumode_handler(); } else { - menuitem_handler(); + menuitem_handler(); } ports_buttons_clear(); } -struct menu* menu_add_entry(char const *name, - void (*up_btn_fn)(void), - void (*down_btn_fn)(void), - void (*num_btn_fn)(void), - void (*lstar_btn_fn)(void), - void (*lnum_btn_fn)(void), - void (*updown_btn_fn)(void), - void (*activate_fn)(void), - void (*deactivate_fn)(void)) +struct menu *menu_add_entry(char const *name, + void (*up_btn_fn) (void), + void (*down_btn_fn) (void), + void (*num_btn_fn) (void), + void (*lstar_btn_fn) (void), + void (*lnum_btn_fn) (void), + void (*updown_btn_fn) (void), + void (*activate_fn) (void), + void (*deactivate_fn) (void)) { struct menu **menu_hd = &menu_head; struct menu *menu_p; - if (! *menu_hd) { - /* Head is empty, create new menu item linked to itself */ - menu_p = (struct menu *) malloc(sizeof(struct menu)); - menu_p->next = menu_p; - menu_p->prev = menu_p; - *menu_hd = menu_p; + if (!*menu_hd) { + /* Head is empty, create new menu item linked to itself */ + menu_p = (struct menu *) malloc(sizeof(struct menu)); + menu_p->next = menu_p; + menu_p->prev = menu_p; + *menu_hd = menu_p; - /* There wasnt any menu active, so we activate this one */ - menumode.item = menu_p; - activate_fn(); + /* There wasnt any menu active, so we activate this one */ + menumode.item = menu_p; + activate_fn(); } else { - /* insert new item before head */ - menu_p = (struct menu *) malloc(sizeof(struct menu)); - menu_p->next = (*menu_hd); - menu_p->prev = (*menu_hd)->prev; - (*menu_hd)->prev = menu_p; - menu_p->prev->next = menu_p; + /* insert new item before head */ + menu_p = (struct menu *) malloc(sizeof(struct menu)); + menu_p->next = (*menu_hd); + menu_p->prev = (*menu_hd)->prev; + (*menu_hd)->prev = menu_p; + menu_p->prev->next = menu_p; } menu_p->name = name; @@ -291,9 +301,9 @@ struct menu* menu_add_entry(char const *name, return menu_p; } -void menu_editmode_start(void (* complete_fn)(void), - void (* cancel_fn)(void), - struct menu_editmode_item *items) +void menu_editmode_start(void (*complete_fn) (void), + void (*cancel_fn) (void), + struct menu_editmode_item *items) { menu_editmode.pos = 0; menu_editmode.items = items; diff --git a/menu.h b/menu.h index 2ccf547..b65d095 100644 --- a/menu.h +++ b/menu.h @@ -42,25 +42,24 @@ \note This function is NULL safe. You can set all of its parameters to NULL (except name) if you don't need their functionality. \note The name string cannot be longer than 5 characters due to the LCD screen size. */ -struct menu * menu_add_entry( - char const * name, /*!< item name to be displayed in the menu */ - void (*up_btn_fn)(void), /*!< callback for up button presses. */ - void (*down_btn_fn)(void), /*!< callback for down button presses. */ - void (*num_btn_fn)(void), /*!< callback for num button presses. */ - void (*lstar_btn_fn)(void), /*!< callback for long star button presses. */ - void (*lnum_btn_fn)(void), /*!< callback for long num button presses. */ - void (*updown_btn_fn)(void),/*!< callback for up&down button presses. */ - void (*activate_fn)(void), /*!< callback for when the user switches into this entry in the menu. */ - void (*deactivate_fn)(void) /*!< callback for when the user switches out from this entry in the menu. */ -); +struct menu *menu_add_entry(char const *name, /*!< item name to be displayed in the menu */ + void (*up_btn_fn) (void), /*!< callback for up button presses. */ + void (*down_btn_fn) (void), /*!< callback for down button presses. */ + void (*num_btn_fn) (void), /*!< callback for num button presses. */ + void (*lstar_btn_fn) (void), /*!< callback for long star button presses. */ + void (*lnum_btn_fn) (void), /*!< callback for long num button presses. */ + void (*updown_btn_fn) (void), /*!< callback for up&down button presses. */ + void (*activate_fn) (void), /*!< callback for when the user switches into this entry in the menu. */ + void (*deactivate_fn) (void) /*!< callback for when the user switches out from this entry in the menu. */ + ); /*! \brief A item structure for menu_editmode_start. */ struct menu_editmode_item { - void (* select)(void); /*!< item selected callback */ - void (* deselect)(void); /*!< item deselected callback */ - void (* set)(int8_t step); /*!< set value of item callback */ + void (*select) (void); /*!< item selected callback */ + void (*deselect) (void); /*!< item deselected callback */ + void (*set) (int8_t step); /*!< set value of item callback */ }; /*! @@ -69,34 +68,33 @@ struct menu_editmode_item { See modules/alarm.c for an example how to use this. */ void menu_editmode_start( - /*! callback for when the user exits from the edit mode.*/ - void (* complete_fn)(void), - /*! callback for when the idle count canceles the edit mode.*/ - void (* cancel_fn)(void), - /*! A vector of #menu_editmode_item, it must be NULL terminated! */ - struct menu_editmode_item *items -); + /*! callback for when the user exits from the edit mode. */ + void (*complete_fn) (void), + /*! callback for when the idle count canceles the edit mode. */ + void (*cancel_fn) (void), + /*! A vector of #menu_editmode_item, it must be NULL terminated! */ + struct menu_editmode_item *items); /* Menu definitions and declarations */ struct menu { /* menu item name */ - char const * name; + char const *name; /* Pointer to up button handler */ - void (*up_btn_fn)(void); + void (*up_btn_fn) (void); /* Pointer to down button handler */ - void (*down_btn_fn)(void); + void (*down_btn_fn) (void); /* Pointer to function button (NUM) */ - void (*num_btn_fn)(void); + void (*num_btn_fn) (void); /* Pointer to settings button (long STAR) */ - void (*lstar_btn_fn)(void); + void (*lstar_btn_fn) (void); /* Pointer to function button (long NUM) */ - void (*lnum_btn_fn)(void); + void (*lnum_btn_fn) (void); /* Pointer to simultaneous up&down press */ - void (*updown_btn_fn)(void); + void (*updown_btn_fn) (void); /* Pointer to activate function */ - void (*activate_fn)(void); + void (*activate_fn) (void); /* Pointer to deactivate function */ - void (*deactivate_fn)(void); + void (*deactivate_fn) (void); /* pointer to next menu item */ struct menu *next; struct menu *prev; @@ -105,4 +103,4 @@ struct menu { void menu_check_buttons(void); void menu_timeout_poll(void); -#endif /* __MENU_H__ */ +#endif /* __MENU_H__ */ diff --git a/messagebus.c b/messagebus.c index 47bc677..c6fde50 100644 --- a/messagebus.c +++ b/messagebus.c @@ -30,14 +30,14 @@ static struct sys_messagebus *messagebus; /*************************************************************************** ************************* THE SYSTEM MESSAGE BUS ************************** **************************************************************************/ -void sys_messagebus_register(void (*callback)(enum sys_message), - enum sys_message listens) +void sys_messagebus_register(void (*callback) (enum sys_message), + enum sys_message listens) { struct sys_messagebus **p = &messagebus; while (*p) { - /* Set p to address of next pointer */ - p = &(*p)->next; + /* Set p to address of next pointer */ + p = &(*p)->next; } *p = malloc(sizeof(struct sys_messagebus)); @@ -46,56 +46,56 @@ void sys_messagebus_register(void (*callback)(enum sys_message), (*p)->listens = listens; } -void sys_messagebus_unregister_all(void (*callback)(enum sys_message)) +void sys_messagebus_unregister_all(void (*callback) (enum sys_message)) { - sys_messagebus_unregister(callback, 0); + sys_messagebus_unregister(callback, 0); } -void sys_messagebus_unregister(void (*callback)(enum sys_message), - enum sys_message listens) +void sys_messagebus_unregister(void (*callback) (enum sys_message), + enum sys_message listens) { struct sys_messagebus *p = messagebus, *pp = NULL; while (p) { - if (p->fn == callback && (listens == 0 || p->listens == listens)) { - if (!pp) { // If 1. element - // Remove first element by pointing to the next - messagebus = p->next; - // Free element - free(p); - // Set current pointer to point to new first element - p = messagebus; - // Keep pp the same (NULL) - } else { // If 2. or later element - // Remove element by pointing previous to the next - pp->next = p->next; - // Free element - free(p); - // Set current pointer to point to next element - p = pp->next; - // Keep pp the same - } - } else { - // Set pp (previous pointer) to current element - pp = p; - // Set p (current pointer) to next element - p = p->next; - } + if (p->fn == callback && (listens == 0 || p->listens == listens)) { + if (!pp) { // If 1. element + // Remove first element by pointing to the next + messagebus = p->next; + // Free element + free(p); + // Set current pointer to point to new first element + p = messagebus; + // Keep pp the same (NULL) + } else { // If 2. or later element + // Remove element by pointing previous to the next + pp->next = p->next; + // Free element + free(p); + // Set current pointer to point to next element + p = pp->next; + // Keep pp the same + } + } else { + // Set pp (previous pointer) to current element + pp = p; + // Set p (current pointer) to next element + p = p->next; + } } } + void send_events(enum sys_message msg) { struct sys_messagebus *p = messagebus; while (p) { - /* notify listener if he registered for any of these messages */ - enum sys_message filtered_msg = msg & p->listens; - if (filtered_msg) { - p->fn(filtered_msg); - } - - /* move to next */ - p = p->next; + /* notify listener if he registered for any of these messages */ + enum sys_message filtered_msg = msg & p->listens; + if (filtered_msg) { + p->fn(filtered_msg); + } + + /* move to next */ + p = p->next; } } - diff --git a/messagebus.h b/messagebus.h index dc3209e..11501de 100644 --- a/messagebus.h +++ b/messagebus.h @@ -44,23 +44,23 @@ If you need to add a new entry, append it to the end! */ enum sys_message { /* drivers/rtca */ - SYS_MSG_NONE = 0, /*!< Empty event. */ - SYS_MSG_RTC_ALARM = BIT0, /*!< alarm event from the hardware RTC. */ - SYS_MSG_RTC_SECOND = BIT1, /*!< second event from the hardware RTC. */ - SYS_MSG_RTC_MINUTE = BIT2, /*!< minute event from the hardware RTC. */ - SYS_MSG_RTC_HOUR = BIT3, /*!< hour event from the hardware RTC. */ - SYS_MSG_RTC_DAY = BIT4, /*!< day event from the hardware RTC. */ - SYS_MSG_RTC_MONTH = BIT5, /*!< month event from the hardware RTC. */ - SYS_MSG_RTC_YEAR = BIT6, /*!< year event from the hardware RTC. */ + SYS_MSG_NONE = 0, /*!< Empty event. */ + SYS_MSG_RTC_ALARM = BIT0, /*!< alarm event from the hardware RTC. */ + SYS_MSG_RTC_SECOND = BIT1, /*!< second event from the hardware RTC. */ + SYS_MSG_RTC_MINUTE = BIT2, /*!< minute event from the hardware RTC. */ + SYS_MSG_RTC_HOUR = BIT3, /*!< hour event from the hardware RTC. */ + SYS_MSG_RTC_DAY = BIT4, /*!< day event from the hardware RTC. */ + SYS_MSG_RTC_MONTH = BIT5, /*!< month event from the hardware RTC. */ + SYS_MSG_RTC_YEAR = BIT6, /*!< year event from the hardware RTC. */ /* drivers/timer */ - SYS_MSG_TIMER_4S = BIT7, /*!< 4s (period) event from the hardware TIMER_0. */ - SYS_MSG_TIMER_20HZ = BIT8, /*!< 20HZ event from the hardware TIMER_0. */ - SYS_MSG_TIMER_PROG = BIT9, /*!< programmable event from TIMER_0. */ + SYS_MSG_TIMER_4S = BIT7, /*!< 4s (period) event from the hardware TIMER_0. */ + SYS_MSG_TIMER_20HZ = BIT8, /*!< 20HZ event from the hardware TIMER_0. */ + SYS_MSG_TIMER_PROG = BIT9, /*!< programmable event from TIMER_0. */ /* sensor/interrups */ - SYS_MSG_AS_INT = BITA, - SYS_MSG_PS_INT = BITB, - SYS_MSG_BATT = BITC, - SYS_MSG_BUTTON = BITD, + SYS_MSG_AS_INT = BITA, + SYS_MSG_PS_INT = BITB, + SYS_MSG_BATT = BITC, + SYS_MSG_BUTTON = BITD, }; /*! @@ -68,7 +68,7 @@ enum sys_message { */ struct sys_messagebus { /*! callback for receiving messages from the system bus */ - void (*fn)(enum sys_message); + void (*fn) (enum sys_message); /*! bitfield of message types that the node wishes to receive */ enum sys_message listens; /*! pointer to the next node in the list */ @@ -81,38 +81,34 @@ struct sys_messagebus { \sa sys_message, sys_messagebus, sys_messagebus_unregister */ void sys_messagebus_register( - /*! callback to receive messages from the message bus */ - void (*callback)(enum sys_message), - /*! only receive messages of this type */ - enum sys_message listens -); + /*! callback to receive messages from the message bus */ + void (*callback) (enum sys_message), + /*! only receive messages of this type */ + enum sys_message listens); /*! \brief Unregisters a node from the message bus. \sa sys_messagebus_register */ void sys_messagebus_unregister_all( - /*! the same callback used on sys_messagebus_register() */ - void (*callback)(enum sys_message) -); + /*! the same callback used on sys_messagebus_register() */ + void (*callback) (enum sys_message) + ); /*! \brief Unregisters a node from the message bus. \sa sys_messagebus_register */ void sys_messagebus_unregister( - /*! the same callback used on sys_messagebus_register() */ - void (*callback)(enum sys_message), - /*! the same message used on sys_messagebus_register() */ - enum sys_message listens -); + /*! the same callback used on sys_messagebus_register() */ + void (*callback) (enum sys_message), + /*! the same message used on sys_messagebus_register() */ + enum sys_message listens); /*! \brief Send a message to all listening nodes on the message bus. \sa sys_messagebus_register, sys_messagebus_unregister */ -void send_events( - enum sys_message msg -); +void send_events(enum sys_message msg); -#endif /* __MESSAGEBUS_H__ */ +#endif /* __MESSAGEBUS_H__ */ diff --git a/modules/accelerometer.c b/modules/accelerometer.c deleted file mode 100644 index 385a110..0000000 --- a/modules/accelerometer.c +++ /dev/null @@ -1,499 +0,0 @@ -/** - modules/accelerometer.c: Accelerometer for Openchronos - - Copyright (C) 2011-2012 Paolo Di Prodi - Copyright (C) 2016 Benjamin Sølberg - - http://github.com/BenjaminSoelberg/openchronos-ng-elf - - This file is part of openchronos-ng. - - openchronos-ng 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. - - openchronos-ng 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 . -**/ - -#include "messagebus.h" -#include "menu.h" - -/* drivers */ -#include "drivers/rtca.h" -#include "drivers/display.h" -#include "drivers/vti_as.h" -#include "drivers/buzzer.h" - -// ************************************************************************************************* -// Defines section - -#define BIT(x) (1uL << (x)) - -#define ACCEL_MODE_OFF (0u) -#define ACCEL_MODE_ON (1u) -#define ACCEL_MODE_BACKGROUND (2u) - -#define DISPLAY_ACCEL_X (0u) -#define DISPLAY_ACCEL_Y (1u) -#define DISPLAY_ACCEL_Z (2u) - -// Stop acceleration measurement after 60 minutes to save battery -// This parameter is ignored if in background mode! -#define ACCEL_MEASUREMENT_TIMEOUT (60u) - -// Conversion values from data to mgrav taken from CMA3000-D0x datasheet (rev 0.4, table 4) -const uint16_t mgrav_per_bit[7] = { 18, 36, 71, 143, 286, 571, 1142 }; - - -// *** Tunes for accelerometer synestesia - -static note smb[] = {0x2588, 0x000F}; - -// ************************************************************************************************* -// Global Variable section -struct accel -{ - // ACC_MODE_OFF, ACC_MODE_ON, ACCEL_MODE_BACKGROUND - uint8_t mode; - - // Sensor raw data - uint8_t xyz[3]; - - - - // Acceleration data in 10 * mgrav - uint16_t data; - - // Sensor old data for FIR filter - uint16_t data_prev; - - // Timeout: should be decreased with the 1 minute RTC event - uint16_t timeout; - // Display X/Y/Z values - uint8_t view_style; -}; -extern struct accel sAccel; - - - -static enum { - VIEW_SET_MODE = 0, - VIEW_SET_PARAMS, - VIEW_STATUS, - VIEW_AXIS, - VIEWMODE_MAX -} submenu_state; - - -struct accel sAccel; - -// Global flag for proper acceleration sensor operation -extern uint8_t as_ok; - -// ************************************************************************************************* -// @fn is_acceleration_measurement -// @brief Returns 1 if acceleration is currently measured. -// @param none -// @return u8 1 = acceleration measurement ongoing -// ************************************************************************************************* -uint8_t is_acceleration_measurement(void) -{ - return ((sAccel.mode == ACCEL_MODE_ON) && (sAccel.timeout > 0)); -} - -// ************************************************************************************************* -// @fn acceleration_value_is_positive -// @brief Returns 1 if 2's complement number is positive -// @param u8 value 2's complement number -// @return u8 1 = number is positive, 0 = number is negavtive -// ************************************************************************************************* -uint8_t acceleration_value_is_positive(uint8_t value) -{ - return ((value & (BIT7)) == 0); -} - - -// ************************************************************************************************* -// @fn convert_acceleration_value_to_mgrav -// @brief Converts measured value to mgrav units -// @param u8 value g data from sensor -// @return u16 Acceleration (mgrav) -// ************************************************************************************************* -uint16_t convert_acceleration_value_to_mgrav(uint8_t value) -{ - uint16_t result; - uint8_t i; - - if (!acceleration_value_is_positive(value)) - { - // Convert 2's complement negative number to positive number - value = ~value; - value += 1; - } - - result = 0; - for (i=0; i<7; i++) - { - - result += ((value & (BIT(i)))>>i) * mgrav_per_bit[i]; - } - - return (result); -} - -void update_menu() -{ - // Depending on the state what do we do? - switch (submenu_state) { - case VIEW_SET_MODE: - - if(as_config.mode==FALL_MODE) - display_chars(0, LCD_SEG_L1_3_0 , "FALL", SEG_SET); - else if(as_config.mode==MEASUREMENT_MODE) - display_chars(0, LCD_SEG_L1_3_0 , "MEAS", SEG_SET); - else if(as_config.mode==ACTIVITY_MODE) - display_chars(0, LCD_SEG_L1_3_0 , "ACTI", SEG_SET); - - display_chars(0, LCD_SEG_L2_4_0 , "MODE", SEG_SET); - break; - - case VIEW_SET_PARAMS: - - display_chars(0, LCD_SEG_L2_5_0 , "SETS", SEG_SET); - break; - - case VIEW_STATUS: - - display_chars(0,LCD_SEG_L2_5_0 , "STAT", SEG_SET); - break; - - case VIEW_AXIS: - - display_chars(0,LCD_SEG_L2_5_0 , "DATA", SEG_SET); - break; - - default: - break; - } - -} - -/* NUM (#) button pressed callback */ -// This change the sub menu -static void num_pressed() -{ - // Change the sub menu code - submenu_state++; - submenu_state %= VIEWMODE_MAX; - // now update the menu - update_menu(); - - -} - -static void up_btn() -{ - - // Depending on the state what do we do? - switch (submenu_state) { - case VIEW_SET_MODE: - as_config.mode++; - as_config.mode %= 3; - change_mode(as_config.mode); - update_menu(); - - break; - - case VIEW_SET_PARAMS: - _printf(0,LCD_SEG_L1_3_0 , "%04x", as_read_register(ADDR_CTRL)); - break; - - case VIEW_STATUS: - _printf(0,LCD_SEG_L1_3_0, "%1u", as_status.all_flags); - - break; - - case VIEW_AXIS: - - display_chars(0,LCD_SEG_L1_3_0 , "TODO", SEG_SET); - break; - - default: - break; - } - /* update menu screen */ - lcd_screen_activate(0); -} - -static void down_btn() -{ - //not necessary at the moment - /* update menu screen */ - lcd_screen_activate(0); -} - -/* Star button long press callback. */ -// This set/unset the background mode -static void star_long_pressed() -{ - if(sAccel.mode==ACCEL_MODE_ON) - { - sAccel.mode = ACCEL_MODE_BACKGROUND; - //set the R symbol on so that is propagated when the user leaves the mode - display_symbol(0, LCD_ICON_RECORD, SEG_SET | BLINK_ON); - } - else if(sAccel.mode==ACCEL_MODE_BACKGROUND) - { - - sAccel.mode = ACCEL_MODE_ON; - //unset the R symbol - display_symbol(0, LCD_ICON_RECORD, SEG_SET | BLINK_OFF); - } - /* update menu screen */ - lcd_screen_activate(0); -} - -void display_data(uint8_t display_id) -{ - uint8_t raw_data=0; - uint16_t accel_data=0; - - // Convert X/Y/Z values to mg - switch (sAccel.view_style) - { - case DISPLAY_ACCEL_X: - raw_data = sAccel.xyz[0]; - display_char(display_id,LCD_SEG_L1_3, 'X', SEG_ON); - break; - case DISPLAY_ACCEL_Y: - raw_data = sAccel.xyz[1]; - display_char(display_id,LCD_SEG_L1_3, 'Y', SEG_ON); - break; - case DISPLAY_ACCEL_Z: - raw_data = sAccel.xyz[2]; - display_char(display_id,LCD_SEG_L1_3, 'Z', SEG_ON); - break; - } - - // Filter acceleration - #ifdef FIXEDPOINT - accel_data = (uint16_t)(((sAccel.data_prev * 2) + (sAccel.data * 8)) / 10); - #else - accel_data = (uint16_t)((sAccel.data_prev * 0.2) + (sAccel.data * 0.8)); - #endif - - // Store average acceleration - sAccel.data = sAccel.data_prev; - - // Display acceleration in x.xx format in the second screen this is real time! - display_chars(display_id,LCD_SEG_L1_2_0, _sprintf("%03s", accel_data), SEG_ON); - - // Display sign - if (acceleration_value_is_positive(raw_data)) { - display_symbol(display_id,LCD_SYMB_ARROW_UP, SEG_ON); - display_symbol(display_id,LCD_SYMB_ARROW_DOWN, SEG_OFF); - } else { - display_symbol(display_id,LCD_SYMB_ARROW_UP, SEG_OFF); - display_symbol(display_id,LCD_SYMB_ARROW_DOWN, SEG_ON); - } -} -static void as_event(enum sys_message msg) -{ - - - if ( (msg & SYS_MSG_RTC_MINUTE) == SYS_MSG_RTC_MINUTE) - { - if(sAccel.mode == ACCEL_MODE_ON) sAccel.timeout--; - //if timeout is over disable the accelerometer - if(sAccel.timeout<1) - { - //disable accelerometer to save power - as_stop(); - //update the mode to remember - sAccel.mode = ACCEL_MODE_OFF; - } - - } - if ( (msg & SYS_MSG_AS_INT) == SYS_MSG_AS_INT) - { - //Check the vti register for status information - as_status.all_flags=as_get_status(); - //TODO For debugging only - _printf(0, LCD_SEG_L1_1_0, "%1u", as_status.all_flags); - buzzer_play(smb); - //if we were in free fall or motion detection mode check for the event - if(as_status.int_status.falldet || as_status.int_status.motiondet){ - - //if such an event is detected enable the symbol - //display_symbol(0, LCD_ICON_ALARM , SEG_SET | BLINK_ON); - - //read the data - as_get_data(sAccel.xyz); - //display_data(0); - /* update menu screen */ - lcd_screen_activate(0); - - }//if we were in measurment mode do a measurement and put it in the virtual screen - else - { - - //display_symbol(0, LCD_ICON_ALARM , SEG_SET | BLINK_OFF); - display_data(1); - /* refresh to accelerometer screen only if in that modality */ - if (submenu_state== VIEW_AXIS )lcd_screen_activate(1); - - } - } - /* The 1 Hz timer is used to refresh the menu screen */ - if ( (msg & SYS_MSG_RTC_SECOND) == SYS_MSG_RTC_SECOND) - { - /*check the status register for debugging purposes */ - _printf(0, LCD_SEG_L1_1_0, "%1u", as_read_register(ADDR_INT_STATUS)); - /* update menu screen */ - lcd_screen_activate(0); - } - -} - -/* Enter the accelerometer menu */ -static void acc_activated() -{ - - - //register to the system bus for vti events as well as the RTC minute events - sys_messagebus_register(&as_event, SYS_MSG_AS_INT | SYS_MSG_RTC_MINUTE | SYS_MSG_RTC_SECOND); - - - /* create two screens, the first is always the active one */ - lcd_screens_create(2); - - /* screen 0 will contain the menu structure and screen 1 the raw accelerometer data */ - - // Show warning if acceleration sensor was not initialised properly - if (!as_ok) - { - display_chars(0, LCD_SEG_L1_3_0, "ERR", SEG_SET); - } - else - { - - /* Initialization is required only if not in background mode! */ - if (sAccel.mode != ACCEL_MODE_BACKGROUND) - { - // Clear previous acceleration value - sAccel.data = 0; - // 2 g range - as_config.range=2; - // 100 Hz sampling rate - as_config.sampling=SAMPLING_10_HZ; - // keep mode - as_config.mode=ACTIVITY_MODE; - //time window is 10 msec for free fall and 100 msec for activity - //2g multiple 71 mg: 0F=4 * 71 mg= 1.065 g - as_config.MDTHR=2; - as_config.MDFFTMR=1; - - // Set timeout counter - sAccel.timeout = ACCEL_MEASUREMENT_TIMEOUT; - - // Set mode for screen - sAccel.mode = ACCEL_MODE_ON; - - // Start with mode selection - submenu_state=VIEW_SET_MODE; - - // Select Axis X - sAccel.view_style=DISPLAY_ACCEL_Z; - - // Start sensor in motion detection mode - as_start(ACTIVITY_MODE); - // After this call interrupts will be generated - } - - if (!as_ok) - { - display_chars(0, LCD_SEG_L1_3_0, "FAIL", SEG_SET); - } - display_chars(0, LCD_SEG_L1_3_0 , "ACTI", SEG_SET); - display_chars(0, LCD_SEG_L2_4_0 , "MODE", SEG_SET); - - - } - /* return to main screen */ - lcd_screen_activate(0); -} - -void print_debug() -{ - // check if that is really in the mode we set - - _printf(0, LCD_SEG_L1_3_0, "%03x", as_read_register(ADDR_CTRL)); - _printf(0, LCD_SEG_L2_5_0, "%05x", as_read_register(ADDR_MDFFTMR)); - -} - - -/* Exit the accelerometer menu. */ -/* Here we could decide to keep it in the background or not and -** also check when activated if it was in background */ - -static void acc_deactivated() -{ - - - /* destroy virtual screens */ - lcd_screens_destroy(); - - /* clean up screen */ - - display_clear(0, 1); - display_clear(0, 2); - - - /* do not disable anything if in background mode */ - if (sAccel.mode == ACCEL_MODE_BACKGROUND) return; - else /* clear symbols only if not in backround mode*/ - //display_symbol(0, LCD_ICON_ALARM , SEG_SET | BLINK_OFF); - - /* otherwise shutdown all the stuff - ** deregister from the message bus */ - sys_messagebus_unregister_all(&as_event); - /* Stop acceleration sensor */ - as_stop(); - - /* Clear mode */ - sAccel.mode = ACCEL_MODE_OFF; -} - - - -void mod_accelerometer_init() -{ - - //if this is called only one time after reboot there are some important things to initialise - //Initialise sAccel struct? - sAccel.data=0; - sAccel.data_prev=0; - // Set timeout counter - sAccel.timeout = ACCEL_MEASUREMENT_TIMEOUT; - /* Clear mode */ - sAccel.mode = ACCEL_MODE_OFF; - - menu_add_entry("ACC", - &up_btn, - &down_btn, - &num_pressed, - &star_long_pressed, - NULL, - NULL, - &acc_activated, - &acc_deactivated); - -} diff --git a/modules/accelerometer.cfg b/modules/accelerometer.cfg deleted file mode 100644 index 24f091a..0000000 --- a/modules/accelerometer.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[ACCELEROMETER] -menu_order = 70 -name = Accelerometer code [EXPERIMENTAL] -help = Provides accelerometer functions diff --git a/modules/accelerometer_b.c b/modules/accelerometer_b.c new file mode 100644 index 0000000..39fc30e --- /dev/null +++ b/modules/accelerometer_b.c @@ -0,0 +1,480 @@ +/** + modules/accelerometer.c: Accelerometer for Openchronos + + Copyright (C) 2011-2012 Paolo Di Prodi + Copyright (C) 2016 Benjamin Sølberg + + http://github.com/BenjaminSoelberg/openchronos-ng-elf + + This file is part of openchronos-ng. + + openchronos-ng 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. + + openchronos-ng 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 . +**/ + +#include "messagebus.h" +#include "menu.h" + +/* drivers */ +#include "drivers/rtca.h" +#include "drivers/display.h" +#include "drivers/vti_as.h" +#include "drivers/buzzer.h" + +// ************************************************************************************************* +// Defines section + +#define BIT(x) (1uL << (x)) + +#define ACCEL_MODE_OFF (0u) +#define ACCEL_MODE_ON (1u) +#define ACCEL_MODE_BACKGROUND (2u) + +#define DISPLAY_ACCEL_X (0u) +#define DISPLAY_ACCEL_Y (1u) +#define DISPLAY_ACCEL_Z (2u) + +// Stop acceleration measurement after 60 minutes to save battery +// This parameter is ignored if in background mode! +#define ACCEL_MEASUREMENT_TIMEOUT (60u) + +// Conversion values from data to mgrav taken from CMA3000-D0x datasheet (rev 0.4, table 4) +const uint16_t mgrav_per_bit[7] = { 18, 36, 71, 143, 286, 571, 1142 }; + + +// *** Tunes for accelerometer synestesia + +static note smb[] = { 0x2588, 0x000F }; + +// ************************************************************************************************* +// Global Variable section +struct accel { + // ACC_MODE_OFF, ACC_MODE_ON, ACCEL_MODE_BACKGROUND + uint8_t mode; + + // Sensor raw data + uint8_t xyz[3]; + + + + // Acceleration data in 10 * mgrav + uint16_t data; + + // Sensor old data for FIR filter + uint16_t data_prev; + + // Timeout: should be decreased with the 1 minute RTC event + uint16_t timeout; + // Display X/Y/Z values + uint8_t view_style; +}; +extern struct accel sAccel; + + + +static enum { + VIEW_SET_MODE = 0, + VIEW_SET_PARAMS, + VIEW_STATUS, + VIEW_AXIS, + VIEWMODE_MAX +} submenu_state; + + +struct accel sAccel; + + +// ************************************************************************************************* +// @fn is_acceleration_measurement +// @brief Returns 1 if acceleration is currently measured. +// @param none +// @return u8 1 = acceleration measurement ongoing +// ************************************************************************************************* +uint8_t is_acceleration_measurement(void) +{ + return ((sAccel.mode == ACCEL_MODE_ON) && (sAccel.timeout > 0)); +} + +// ************************************************************************************************* +// @fn acceleration_value_is_positive +// @brief Returns 1 if 2's complement number is positive +// @param u8 value 2's complement number +// @return u8 1 = number is positive, 0 = number is negavtive +// ************************************************************************************************* +uint8_t acceleration_value_is_positive(uint8_t value) +{ + return ((value & (BIT7)) == 0); +} + + +// ************************************************************************************************* +// @fn convert_acceleration_value_to_mgrav +// @brief Converts measured value to mgrav units +// @param u8 value g data from sensor +// @return u16 Acceleration (mgrav) +// ************************************************************************************************* +uint16_t convert_acceleration_value_to_mgrav(uint8_t value) +{ + uint16_t result; + uint8_t i; + + if (!acceleration_value_is_positive(value)) { + // Convert 2's complement negative number to positive number + value = ~value; + value += 1; + } + + result = 0; + for (i = 0; i < 7; i++) { + + result += ((value & (BIT(i))) >> i) * mgrav_per_bit[i]; + } + + return (result); +} + +void update_menu() +{ + // Depending on the state what do we do? + switch (submenu_state) { + case VIEW_SET_MODE: + + if (as_config.mode == FALL_MODE) + display_chars(0, LCD_SEG_L1_3_0, "FALL", SEG_SET); + else if (as_config.mode == MEASUREMENT_MODE) + display_chars(0, LCD_SEG_L1_3_0, "MEAS", SEG_SET); + else if (as_config.mode == ACTIVITY_MODE) + display_chars(0, LCD_SEG_L1_3_0, "ACTI", SEG_SET); + + display_chars(0, LCD_SEG_L2_4_0, "MODE", SEG_SET); + break; + + case VIEW_SET_PARAMS: + + display_chars(0, LCD_SEG_L2_4_0, "SETS", SEG_SET); + break; + + case VIEW_STATUS: + + display_chars(0, LCD_SEG_L2_4_0, "STAT", SEG_SET); + break; + + case VIEW_AXIS: + + display_chars(0, LCD_SEG_L2_4_0, "DATA", SEG_SET); + break; + + default: + break; + } + +} + +/* NUM (#) button pressed callback */ +// This change the sub menu +static void num_pressed() +{ + // Change the sub menu code + submenu_state++; + submenu_state %= VIEWMODE_MAX; + // now update the menu + update_menu(); + + +} + +static void up_btn() +{ + + // Depending on the state what do we do? + switch (submenu_state) { + case VIEW_SET_MODE: + as_config.mode++; + as_config.mode %= 3; + change_mode(as_config.mode); + update_menu(); + + break; + + case VIEW_SET_PARAMS: + _printf(0, LCD_SEG_L1_3_0, "%04x", as_read_register(ADDR_CTRL)); + break; + + case VIEW_STATUS: + _printf(0, LCD_SEG_L1_3_0, "%1u", as_status.all_flags); + + break; + + case VIEW_AXIS: + + display_chars(0, LCD_SEG_L1_3_0, "TODO", SEG_SET); + break; + + default: + break; + } + /* update menu screen */ + lcd_screen_activate(0); +} + +static void down_btn() +{ + //not necessary at the moment + /* update menu screen */ + lcd_screen_activate(0); +} + +/* Star button long press callback. */ +// This set/unset the background mode +static void star_long_pressed() +{ + if (sAccel.mode == ACCEL_MODE_ON) { + sAccel.mode = ACCEL_MODE_BACKGROUND; + //set the R symbol on so that is propagated when the user leaves the mode + display_symbol(0, LCD_ICON_RECORD, SEG_SET | BLINK_ON); + } else if (sAccel.mode == ACCEL_MODE_BACKGROUND) { + + sAccel.mode = ACCEL_MODE_ON; + //unset the R symbol + display_symbol(0, LCD_ICON_RECORD, SEG_SET | BLINK_OFF); + } + /* update menu screen */ + lcd_screen_activate(0); +} + +void display_data(uint8_t display_id) +{ + uint8_t raw_data = 0; + uint16_t accel_data = 0; + + // Convert X/Y/Z values to mg + switch (sAccel.view_style) { + case DISPLAY_ACCEL_X: + raw_data = sAccel.xyz[0]; + display_char(display_id, LCD_SEG_L1_3, 'X', SEG_ON); + break; + case DISPLAY_ACCEL_Y: + raw_data = sAccel.xyz[1]; + display_char(display_id, LCD_SEG_L1_3, 'Y', SEG_ON); + break; + case DISPLAY_ACCEL_Z: + raw_data = sAccel.xyz[2]; + display_char(display_id, LCD_SEG_L1_3, 'Z', SEG_ON); + break; + } + + // Filter acceleration +#ifdef FIXEDPOINT + accel_data = + (uint16_t) (((sAccel.data_prev * 2) + (sAccel.data * 8)) / 10); +#else + accel_data = + (uint16_t) ((sAccel.data_prev * 0.2) + (sAccel.data * 0.8)); +#endif + + // Store average acceleration + sAccel.data = sAccel.data_prev; + + // Display acceleration in x.xx format in the second screen this is real time! + display_chars(display_id, LCD_SEG_L1_2_0, _sprintf("%03s", accel_data), + SEG_ON); + + // Display sign + if (acceleration_value_is_positive(raw_data)) { + display_symbol(display_id, LCD_SYMB_ARROW_UP, SEG_ON); + display_symbol(display_id, LCD_SYMB_ARROW_DOWN, SEG_OFF); + } else { + display_symbol(display_id, LCD_SYMB_ARROW_UP, SEG_OFF); + display_symbol(display_id, LCD_SYMB_ARROW_DOWN, SEG_ON); + } +} + +static void as_event(enum sys_message msg) +{ + + + if ((msg & SYS_MSG_RTC_MINUTE) == SYS_MSG_RTC_MINUTE) { + if (sAccel.mode == ACCEL_MODE_ON) + sAccel.timeout--; + //if timeout is over disable the accelerometer + if (sAccel.timeout < 1) { + //disable accelerometer to save power + as_stop(); + //update the mode to remember + sAccel.mode = ACCEL_MODE_OFF; + } + + } + if ((msg & SYS_MSG_AS_INT) == SYS_MSG_AS_INT) { + //Check the vti register for status information + as_status.all_flags = as_get_status(); + //TODO For debugging only + _printf(0, LCD_SEG_L1_1_0, "%1u", as_status.all_flags); + buzzer_play(smb); + //if we were in free fall or motion detection mode check for the event + if (as_status.int_status.falldet || as_status.int_status.motiondet) { + + //if such an event is detected enable the symbol + //display_symbol(0, LCD_ICON_ALARM , SEG_SET | BLINK_ON); + + //read the data + as_get_data(sAccel.xyz); + //display_data(0); + /* update menu screen */ + lcd_screen_activate(0); + + } //if we were in measurment mode do a measurement and put it in the virtual screen + else { + + //display_symbol(0, LCD_ICON_ALARM , SEG_SET | BLINK_OFF); + display_data(1); + /* refresh to accelerometer screen only if in that modality */ + if (submenu_state == VIEW_AXIS) + lcd_screen_activate(1); + + } + } + /* The 1 Hz timer is used to refresh the menu screen */ + if ((msg & SYS_MSG_RTC_SECOND) == SYS_MSG_RTC_SECOND) { + /*check the status register for debugging purposes */ + _printf(0, LCD_SEG_L1_1_0, "%1u", + as_read_register(ADDR_INT_STATUS)); + /* update menu screen */ + lcd_screen_activate(0); + } + +} + +/* Enter the accelerometer menu */ +static void acc_activated() +{ + + + //register to the system bus for vti events as well as the RTC minute events + sys_messagebus_register(&as_event, + SYS_MSG_AS_INT | SYS_MSG_RTC_MINUTE | + SYS_MSG_RTC_SECOND); + + + /* create two screens, the first is always the active one */ + lcd_screens_create(2); + + /* screen 0 will contain the menu structure and screen 1 the raw accelerometer data */ + + + /* Initialization is required only if not in background mode! */ + if (sAccel.mode != ACCEL_MODE_BACKGROUND) { + // Clear previous acceleration value + sAccel.data = 0; + // 2 g range + as_config.range = 2; + // 100 Hz sampling rate + as_config.sampling = SAMPLING_10_HZ; + // keep mode + as_config.mode = ACTIVITY_MODE; + //time window is 10 msec for free fall and 100 msec for activity + //2g multiple 71 mg: 0F=4 * 71 mg= 1.065 g + as_config.MDTHR = 2; + as_config.MDFFTMR = 1; + + // Set timeout counter + sAccel.timeout = ACCEL_MEASUREMENT_TIMEOUT; + + // Set mode for screen + sAccel.mode = ACCEL_MODE_ON; + + // Start with mode selection + submenu_state = VIEW_SET_MODE; + + // Select Axis X + sAccel.view_style = DISPLAY_ACCEL_Z; + + // Start sensor in motion detection mode + as_start(ACTIVITY_MODE); + // After this call interrupts will be generated + } + + display_chars(0, LCD_SEG_L1_3_0, "ACTI", SEG_SET); + display_chars(0, LCD_SEG_L2_4_0, "MODE", SEG_SET); + + + + /* return to main screen */ + lcd_screen_activate(0); +} + +void print_debug() +{ + // check if that is really in the mode we set + + _printf(0, LCD_SEG_L1_3_0, "%03x", as_read_register(ADDR_CTRL)); + _printf(0, LCD_SEG_L2_4_0, "%05x", as_read_register(ADDR_MDFFTMR)); + +} + + +/* Exit the accelerometer menu. */ +/* Here we could decide to keep it in the background or not and +** also check when activated if it was in background */ + +static void acc_deactivated() +{ + + + /* destroy virtual screens */ + lcd_screens_destroy(); + + /* clean up screen */ + + display_clear(0, 1); + display_clear(0, 2); + + + /* do not disable anything if in background mode */ + if (sAccel.mode == ACCEL_MODE_BACKGROUND) + return; + else /* clear symbols only if not in backround mode */ + //display_symbol(0, LCD_ICON_ALARM , SEG_SET | BLINK_OFF); + + /* otherwise shutdown all the stuff + ** deregister from the message bus */ + sys_messagebus_unregister_all(&as_event); + /* Stop acceleration sensor */ + as_stop(); + + /* Clear mode */ + sAccel.mode = ACCEL_MODE_OFF; +} + + + +void mod_accelerometer_b_init() +{ + + //if this is called only one time after reboot there are some important things to initialise + //Initialise sAccel struct? + sAccel.data = 0; + sAccel.data_prev = 0; + // Set timeout counter + sAccel.timeout = ACCEL_MEASUREMENT_TIMEOUT; + /* Clear mode */ + sAccel.mode = ACCEL_MODE_OFF; + + menu_add_entry("ACC", + &up_btn, + &down_btn, + &num_pressed, + &star_long_pressed, + NULL, NULL, &acc_activated, &acc_deactivated); + +} diff --git a/modules/accelerometer_b.cfg b/modules/accelerometer_b.cfg new file mode 100644 index 0000000..4c2a0ff --- /dev/null +++ b/modules/accelerometer_b.cfg @@ -0,0 +1,5 @@ +[ACCELEROMETER_B] +menu_order = 11 +name = Accelerometer code [EXPERIMENTAL] +help = Provides accelerometer functions. +depends = BLACK_PCB diff --git a/modules/accelerometer_w.c b/modules/accelerometer_w.c new file mode 100644 index 0000000..e9d7d28 --- /dev/null +++ b/modules/accelerometer_w.c @@ -0,0 +1,182 @@ +/** + modules/accelerometer_w.c: white PCB accelerometer module for openchronos-ng + + Copyright (C) 2019 Luca Lorello + + http://github.com/HashakGik/openchronos-ng-elf + + This file is part of openchronos-ng. + + openchronos-ng 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. + + openchronos-ng 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 . +**/ + +/* This module uses the BMA 250 sensor (white PCB) to calculate various acceleration parameters. + + The up and down keys switch between x axis (default), y axis, z axis, modulus, pitch angle and roll angle measurement. + The # key changes the measurement scale between +-2g (default), +-4g, +-8g and +-16g. + */ + +#include "messagebus.h" +#include "menu.h" + +#include "drivers/display.h" +#include "drivers/as.h" +#include "drivers/bmp_as.h" +#include "drivers/timer.h" + +#include + +static int i; +static int scale; +static int16_t axes[3]; + +static void print_acc(void) +{ + int32_t vals[7]; + uint8_t j; + float scale_factor = ((1 << (scale + 1)) * 100) / 512.0; + uint8_t dec; + int8_t tmp; + + for (j = 0, vals[3] = 0; j < 3; j++) { + vals[j] = axes[j] * scale_factor; + vals[3] += vals[j] * vals[j]; + } + vals[3] = sqrtf(vals[3]); // Modulus of acceleration vector. + vals[4] = atan2f(vals[0], vals[2]) * 5729; // Pitch angle. Convert from rad to deg and multiply by 100. + vals[5] = atan2f(vals[1], vals[2]) * 5729; // Roll angle. + + + display_symbol(0, LCD_SEG_L2_DP, SEG_SET); + switch (i) { + case 0: + display_chars(0, LCD_SEG_L1_3_0, " X ", SEG_SET); + break; + case 1: + display_chars(0, LCD_SEG_L1_3_0, " Y ", SEG_SET); + break; + case 2: + display_chars(0, LCD_SEG_L1_3_0, " Z ", SEG_SET); + break; + case 3: + display_chars(0, LCD_SEG_L1_3_0, "ABSO", SEG_SET); + break; + case 4: + display_chars(0, LCD_SEG_L1_3_0, "PITC", SEG_SET); + break; + case 5: + display_chars(0, LCD_SEG_L1_3_0, "ROLL", SEG_SET); + break; + } + + tmp = vals[i] / 100; + if (vals[i] < 0) + dec = (-vals[i]) % 100; + else + dec = vals[i] % 100; + + if (tmp == 0) + display_char(0, LCD_SEG_L2_2, '0', SEG_SET); + else + _printf(0, LCD_SEG_L2_4_2, "%2s", tmp); + + _printf(0, LCD_SEG_L2_1_0, "%02u", dec); + +} + +static void update_acc(enum sys_message msg) +{ + bmp_as_get_data(axes); + + print_acc(); +} + +static void acc_activate(void) +{ + axes[0] = axes[1] = axes[2] = 0; + scale = 0; + i = 0; + as_init(); + bmp_as_start(BMP_GRANGE_2G, BMP_BWD_62HZ, BMP_SLEEP_1000MS, 0); + timer0_delay(1000, LPM3_bits); + + bmp_as_interrupts_t ints = bmp_as_init_interrupts(); + + //ints.slope_interrupt.x = 1; + //ints.slope_interrupt.y = 1; + //ints.slope_interrupt.z = 1; + // ints.tap_interrupt = 2; + ints.new_interrupt = 1; + bmp_as_enable_interrupts(ints); + + sys_messagebus_register(&update_acc, SYS_MSG_AS_INT); +} + +static void acc_deactivate(void) +{ + display_clear(0, 0); + sys_messagebus_unregister_all(&update_acc); + + bmp_as_disable_interrupts(); + bmp_as_stop(); +} + +static void up_btn(void) +{ + i = (i + 1) % 6; + print_acc(); +} + +static void down_btn(void) +{ + i = (i + 5) % 6; + print_acc(); +} + +static void num_pressed(void) +{ + scale = (scale + 1) % 4; + display_clear(0, 0); + + bmp_as_stop(); + switch (scale) { + case 0: + bmp_as_start(BMP_GRANGE_2G, BMP_BWD_62HZ, BMP_SLEEP_1000MS, 1); + display_chars(0, LCD_SEG_L1_3_0, " 2 G", SEG_SET | BLINK_SET); + break; + case 1: + bmp_as_start(BMP_GRANGE_4G, BMP_BWD_62HZ, BMP_SLEEP_1000MS, 1); + display_chars(0, LCD_SEG_L1_3_0, " 4 G", SEG_SET | BLINK_SET); + break; + case 2: + bmp_as_start(BMP_GRANGE_8G, BMP_BWD_62HZ, BMP_SLEEP_1000MS, 1); + display_chars(0, LCD_SEG_L1_3_0, " 8 G", SEG_SET | BLINK_SET); + break; + case 3: + bmp_as_start(BMP_GRANGE_16G, BMP_BWD_62HZ, BMP_SLEEP_1000MS, 1); + display_chars(0, LCD_SEG_L1_3_0, "16 G", SEG_SET | BLINK_SET); + break; + } + + timer0_delay(1000, LPM3_bits); + display_chars(0, LCD_SEG_L1_3_0, "8888", SEG_OFF | BLINK_OFF); + axes[0] = axes[1] = axes[2] = 0; + print_acc(); +} + +void mod_accelerometer_w_init(void) +{ + menu_add_entry("ACCEL", &up_btn, &down_btn, &num_pressed, NULL, NULL, + NULL, &acc_activate, &acc_deactivate); +} diff --git a/modules/accelerometer_w.cfg b/modules/accelerometer_w.cfg new file mode 100644 index 0000000..7e98697 --- /dev/null +++ b/modules/accelerometer_w.cfg @@ -0,0 +1,5 @@ +[ACCELEROMETER_W] +menu_order = 21 +name = Accelerometer +help = Provides accelerometer functions. +depends = WHITE_PCB \ No newline at end of file diff --git a/modules/alarm.c b/modules/alarm.c index c74c339..76234a6 100644 --- a/modules/alarm.c +++ b/modules/alarm.c @@ -1,25 +1,25 @@ /** - modules/alarm.c: Alarm module for openchronos-ng + modules/alarm.c: Alarm module for openchronos-ng - Copyright (C) 2011-2012 Angelo Arrifano - Copyright (C) 2016 Benjamin Sølberg + Copyright (C) 2011-2012 Angelo Arrifano + Copyright (C) 2016 Benjamin Sølberg - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ #include "messagebus.h" @@ -32,86 +32,79 @@ #include "drivers/ports.h" static union { - struct { - /* one shot alarm */ - uint8_t alarm:1; - /* hourly chime */ - uint8_t chime:1; - }; - uint8_t state:2; + struct { + /* one shot alarm */ + uint8_t alarm:1; + /* hourly chime */ + uint8_t chime:1; + }; + uint8_t state:2; } alarm_state; static uint8_t tmp_hh, tmp_mm; -static note chime_notes[2] = {0x1931, 0x000F}; -static note alarm_notes[4] = {0x3234, 0x1900, 0x3234, 0x000F}; +static note chime_notes[2] = { 0x1931, 0x000F }; +static note alarm_notes[4] = { 0x3234, 0x1900, 0x3234, 0x000F }; -static void print_mm (void) +static void print_mm(void) { - _printf(0, LCD_SEG_L1_1_0, "%02u", tmp_mm); + _printf(0, LCD_SEG_L1_1_0, "%02u", tmp_mm); } static void print_hh(void) { - if (display_am_pm) - { - uint8_t hh = tmp_hh; - if (hh > 12) - { //PM - hh -= 12; - display_symbol (0, LCD_SYMB_PM, SEG_SET); - } - else - { - if (hh == 12) - { // PM - display_symbol (0, LCD_SYMB_PM, SEG_SET); - } - else - { // AM - display_symbol (0, LCD_SYMB_PM, SEG_OFF); - } - if (hh == 0) - hh = 12; - } - _printf(0, LCD_SEG_L1_3_2, "%2u", hh); - } - else - { - _printf(0, LCD_SEG_L1_3_2, "%02u", tmp_hh); - display_symbol (0, LCD_SYMB_PM, SEG_OFF); - } + if (display_am_pm) { + uint8_t hh = tmp_hh; + if (hh > 12) { //PM + hh -= 12; + display_symbol(0, LCD_SYMB_PM, SEG_SET); + } else { + if (hh == 12) { // PM + display_symbol(0, LCD_SYMB_PM, SEG_SET); + } else { // AM + display_symbol(0, LCD_SYMB_PM, SEG_OFF); + } + if (hh == 0) + hh = 12; + } + _printf(0, LCD_SEG_L1_3_2, "%2u", hh); + } else { + _printf(0, LCD_SEG_L1_3_2, "%02u", tmp_hh); + display_symbol(0, LCD_SYMB_PM, SEG_OFF); + } } static void refresh_screen() { - rtca_get_alarm(&tmp_hh, &tmp_mm); - print_hh(); - print_mm(); + rtca_get_alarm(&tmp_hh, &tmp_mm); + print_hh(); + print_mm(); } static uint8_t alarm_sec_elapsed = 0; static void alarm_event(enum sys_message msg) { - if (msg & SYS_MSG_BUTTON || alarm_sec_elapsed >= 30) { - alarm_sec_elapsed = 0; - ports_buttons_clear(); - sys_messagebus_unregister(&alarm_event, SYS_MSG_BUTTON | SYS_MSG_RTC_SECOND); - return; - } + if (msg & SYS_MSG_BUTTON || alarm_sec_elapsed >= 30) { + alarm_sec_elapsed = 0; + ports_buttons_clear(); + sys_messagebus_unregister(&alarm_event, + SYS_MSG_BUTTON | SYS_MSG_RTC_SECOND); + return; + } - if (msg & SYS_MSG_RTC_ALARM) { - sys_messagebus_register(&alarm_event, SYS_MSG_BUTTON | SYS_MSG_RTC_SECOND); - } + if (msg & SYS_MSG_RTC_ALARM) { + sys_messagebus_register(&alarm_event, + SYS_MSG_BUTTON | SYS_MSG_RTC_SECOND); + } - alarm_sec_elapsed++; - buzzer_play(alarm_notes); + alarm_sec_elapsed++; + buzzer_play(alarm_notes); } static void hour_event(enum sys_message msg) { - if (msg & SYS_MSG_RTC_HOUR) { - buzzer_play(chime_notes); - } + if (msg & SYS_MSG_RTC_HOUR) { + buzzer_play(chime_notes); + } } /*************************** edit mode callbacks **************************/ @@ -119,118 +112,115 @@ static void hour_event(enum sys_message msg) /* Hour */ static void edit_hh_sel(void) { - display_chars(0, LCD_SEG_L1_3_2, NULL, BLINK_ON); + display_chars(0, LCD_SEG_L1_3_2, NULL, BLINK_ON); } static void edit_hh_dsel(void) { - display_chars(0, LCD_SEG_L1_3_2, NULL, BLINK_OFF); + display_chars(0, LCD_SEG_L1_3_2, NULL, BLINK_OFF); } static void edit_hh_set(int8_t step) { - helpers_loop(&tmp_hh, 0, 23, step); - print_hh(); + helpers_loop(&tmp_hh, 0, 23, step); + print_hh(); } /* Minute */ static void edit_mm_sel(void) { - display_chars(0, LCD_SEG_L1_1_0, NULL, BLINK_ON); + display_chars(0, LCD_SEG_L1_1_0, NULL, BLINK_ON); } static void edit_mm_dsel(void) { - display_chars(0, LCD_SEG_L1_1_0, NULL, BLINK_OFF); + display_chars(0, LCD_SEG_L1_1_0, NULL, BLINK_OFF); } static void edit_mm_set(int8_t step) { - helpers_loop(&tmp_mm, 0, 59, step); - print_mm(); + helpers_loop(&tmp_mm, 0, 59, step); + print_mm(); } /* Save */ static void edit_save(void) { - /* Here we return from the edit mode, fill in the new values! */ - rtca_set_alarm(tmp_hh, tmp_mm); + /* Here we return from the edit mode, fill in the new values! */ + rtca_set_alarm(tmp_hh, tmp_mm); } /* edit mode item table */ static struct menu_editmode_item edit_items[] = { - {&edit_hh_sel, &edit_hh_dsel, &edit_hh_set}, - {&edit_mm_sel, &edit_mm_dsel, &edit_mm_set}, - { NULL }, + {&edit_hh_sel, &edit_hh_dsel, &edit_hh_set}, + {&edit_mm_sel, &edit_mm_dsel, &edit_mm_set}, + {NULL}, }; /******************** menu callbacks **************************************/ static void alarm_activated() { - /* Force redraw of the screen */ - display_symbol(0, LCD_SEG_L1_COL, SEG_ON); - refresh_screen(); + /* Force redraw of the screen */ + display_symbol(0, LCD_SEG_L1_COL, SEG_ON); + refresh_screen(); } static void alarm_deactivated() { - /* clean up screen */ - display_clear(0, 1); + /* clean up screen */ + display_clear(0, 1); } /* NUM (#) button pressed callback */ static void num_pressed() { - /* this cycles between all alarm/chime combinations and overflow */ - alarm_state.state++; - - rtca_disable_alarm(); - /* Prevents double registration */ - sys_messagebus_unregister(&alarm_event, SYS_MSG_RTC_ALARM); - /* Register RTC alarm event only if needed, saving CPU cycles.. */ - if (alarm_state.alarm) { - display_symbol(0, LCD_ICON_ALARM, SEG_ON); - sys_messagebus_register(&alarm_event, SYS_MSG_RTC_ALARM); - rtca_enable_alarm(); - } else { - display_symbol(0, LCD_ICON_ALARM, SEG_OFF); - } - - /* Prevents double registration */ - sys_messagebus_unregister(&hour_event, SYS_MSG_RTC_HOUR); - /* Register RTC hour event only if needed, saving CPU cycles.. */ - if (alarm_state.chime) { - display_symbol(0, LCD_ICON_BEEPER2, SEG_ON); - display_symbol(0, LCD_ICON_BEEPER3, SEG_ON); - sys_messagebus_register(&hour_event, SYS_MSG_RTC_HOUR); - } else { - display_symbol(0, LCD_ICON_BEEPER2, SEG_OFF); - display_symbol(0, LCD_ICON_BEEPER3, SEG_OFF); - } + /* this cycles between all alarm/chime combinations and overflow */ + alarm_state.state++; + + rtca_disable_alarm(); + /* Prevents double registration */ + sys_messagebus_unregister(&alarm_event, SYS_MSG_RTC_ALARM); + /* Register RTC alarm event only if needed, saving CPU cycles.. */ + if (alarm_state.alarm) { + display_symbol(0, LCD_ICON_ALARM, SEG_ON); + sys_messagebus_register(&alarm_event, SYS_MSG_RTC_ALARM); + rtca_enable_alarm(); + } else { + display_symbol(0, LCD_ICON_ALARM, SEG_OFF); + } + + /* Prevents double registration */ + sys_messagebus_unregister(&hour_event, SYS_MSG_RTC_HOUR); + /* Register RTC hour event only if needed, saving CPU cycles.. */ + if (alarm_state.chime) { + display_symbol(0, LCD_ICON_BEEPER2, SEG_ON); + display_symbol(0, LCD_ICON_BEEPER3, SEG_ON); + sys_messagebus_register(&hour_event, SYS_MSG_RTC_HOUR); + } else { + display_symbol(0, LCD_ICON_BEEPER2, SEG_OFF); + display_symbol(0, LCD_ICON_BEEPER3, SEG_OFF); + } } /* Star button long press callback. */ static void star_long_pressed() { - /* Save the current time in edit_buffer */ - rtca_get_alarm(&tmp_hh, &tmp_mm); + /* Save the current time in edit_buffer */ + rtca_get_alarm(&tmp_hh, &tmp_mm); - menu_editmode_start(&edit_save, NULL, edit_items); + menu_editmode_start(&edit_save, NULL, edit_items); } void mod_alarm_init() { - menu_add_entry ("ALARM", - NULL, - NULL, - &num_pressed, - &star_long_pressed, - NULL, - NULL, - &alarm_activated, - &alarm_deactivated); + menu_add_entry("ALARM", + NULL, + NULL, + &num_pressed, + &star_long_pressed, + NULL, NULL, &alarm_activated, &alarm_deactivated); } diff --git a/modules/alarm.cfg b/modules/alarm.cfg index c5eab3f..d3f64b0 100644 --- a/modules/alarm.cfg +++ b/modules/alarm.cfg @@ -1,6 +1,6 @@ [ALARM] -menu_order = 30 +menu_order = 3 name = Alarm default = true depends = CONFIG_RTC_IRQ -help = Provides hourly notifications and settable alarm +help = Provides hourly notifications and settable alarm. diff --git a/modules/altimeter.c b/modules/altimeter.c new file mode 100644 index 0000000..2af685d --- /dev/null +++ b/modules/altimeter.c @@ -0,0 +1,80 @@ +/** + modules/altimeter.c: white PCB altimeter module for openchronos-ng + + Copyright (C) 2019 Luca Lorello + + http://github.com/HashakGik/openchronos-ng-elf + + This file is part of openchronos-ng. + + openchronos-ng 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. + + openchronos-ng 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 . +**/ + +/* This module uses the BMP085 sensor (white PCB) and the original Texas Instrument functions to calculate current altitude (in m). + */ + + +#include "messagebus.h" +#include "menu.h" + +#include "drivers/display.h" +#include "drivers/bmp_ps.h" +#include "drivers/ps.h" +#include "openchronos.h" +#include "config.h" + +static uint8_t altitude_counter; + +static void update_altitude(enum sys_message msg) +{ + if (altitude_counter == 0) { + int16_t alti = + conv_pa_to_meter(bmp_ps_get_pa(), bmp_ps_get_temp()); + if (alti < 0) { + display_symbol(0, LCD_SYMB_ARROW_DOWN, SEG_SET); + alti = -alti; + } else + display_symbol(0, LCD_SYMB_ARROW_DOWN, SEG_OFF); + + if (alti == 0) + display_chars(0, LCD_SEG_L1_3_0, " 0", SEG_SET); + else + _printf(0, LCD_SEG_L1_3_0, "%4u", alti); + } + altitude_counter = (altitude_counter + 1) % CONFIG_MOD_ALTIMETER_REFRESH; // #include "config.h" +} + +static void alti_init(void) +{ + bmp_ps_init(); + init_pressure_table(); + bmp_ps_start(); + + altitude_counter = 0; + sys_messagebus_register(&update_altitude, SYS_MSG_RTC_SECOND); // The SYS_MSG_PS_INT is generated only after start_altitude_measurement() and the measurement is currently done synchronously via spinlocking, so it's not useful. + display_symbol(0, LCD_UNIT_L1_M, SEG_SET); +} + +static void alti_deac(void) +{ + bmp_ps_stop(); + sys_messagebus_unregister_all(&update_altitude); + display_symbol(0, LCD_UNIT_L1_M, SEG_OFF); +} + +void mod_altimeter_init(void) +{ + menu_add_entry("ALTIT", NULL, NULL, NULL, NULL, NULL, NULL, &alti_init, + &alti_deac); +} diff --git a/modules/altimeter.cfg b/modules/altimeter.cfg new file mode 100644 index 0000000..f228feb --- /dev/null +++ b/modules/altimeter.cfg @@ -0,0 +1,13 @@ +[ALTIMETER] +menu_order = 23 +name = Altimeter module +default = false +help = Provides altimeter functions. +depends = WHITE_PCB + +[ALTIMETER_REFRESH] +name = Altimeter refresh rate +ifndef = true +type = text +default = 60 +help = Altimeter refresh rate (in seconds). \ No newline at end of file diff --git a/modules/battery.c b/modules/battery.c index 22cfa14..c8bf681 100644 --- a/modules/battery.c +++ b/modules/battery.c @@ -1,25 +1,25 @@ /** - battery.c: battery voltage display module + battery.c: battery voltage display module - Copyright (C) 2012 Matthew Excell - Copyright (C) 2016 Benjamin Sølberg + Copyright (C) 2012 Matthew Excell + Copyright (C) 2016 Benjamin Sølberg - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ #include "messagebus.h" @@ -31,65 +31,64 @@ static void display_battery(void) { - /* display battery percentage on line one */ - display_chars(0, LCD_SEG_L1_2_0, _itopct(BATTERY_EMPTY_THRESHOLD, - BATTERY_FULL_THRESHOLD, battery_info.voltage), SEG_SET); + /* display battery percentage on line one */ + display_chars(0, LCD_SEG_L1_2_0, _itopct(BATTERY_EMPTY_THRESHOLD, + BATTERY_FULL_THRESHOLD, + battery_info.voltage), + SEG_SET); #ifdef CONFIG_MOD_BATTERY_SHOW_VOLTAGE - /* display battery voltage in line two (xx.x format) */ - _printf(0, LCD_SEG_L2_3_0, "%4u", battery_info.voltage); + /* display battery voltage in line two (xx.x format) */ + _printf(0, LCD_SEG_L2_3_0, "%4u", battery_info.voltage); #endif } static void battery_event(enum sys_message event) { - display_battery(); + display_battery(); } static void battery_activate(void) { - battery_measurement(); + battery_measurement(); - sys_messagebus_register(&battery_event, SYS_MSG_BATT); + sys_messagebus_register(&battery_event, SYS_MSG_BATT); - /* display static symbols */ + /* display static symbols */ #ifdef CONFIG_MOD_BATTERY_SHOW_VOLTAGE - display_symbol(0, LCD_SEG_L2_DP, SEG_ON); + display_symbol(0, LCD_SEG_L2_DP, SEG_ON); #endif - display_symbol(0, LCD_SYMB_BATTERY, SEG_ON); - display_symbol(0, LCD_SYMB_PERCENT, SEG_ON); + display_symbol(0, LCD_SYMB_BATTERY, SEG_ON); + display_symbol(0, LCD_SYMB_PERCENT, SEG_ON); - /* refresh display */ - display_battery(); + /* refresh display */ + display_battery(); } static void battery_deactivate(void) { - sys_messagebus_unregister_all(&battery_event); + sys_messagebus_unregister_all(&battery_event); - /* cleanup screen */ - display_clear(0, 1); + /* cleanup screen */ + display_clear(0, 1); #ifdef CONFIG_MOD_BATTERY_SHOW_VOLTAGE - display_clear(0, 2); + display_clear(0, 2); #endif - /* clear static symbols */ + /* clear static symbols */ #ifdef CONFIG_MOD_BATTERY_SHOW_VOLTAGE - display_symbol(0, LCD_SEG_L2_DP, SEG_OFF); + display_symbol(0, LCD_SEG_L2_DP, SEG_OFF); #endif - display_symbol(0, LCD_SYMB_PERCENT, SEG_OFF); - display_symbol(0, LCD_SYMB_BATTERY, SEG_OFF); + display_symbol(0, LCD_SYMB_PERCENT, SEG_OFF); + display_symbol(0, LCD_SYMB_BATTERY, SEG_OFF); } void mod_battery_init(void) { - menu_add_entry("BATT", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - &battery_activate, - &battery_deactivate); + menu_add_entry("BATT", + NULL, + NULL, + NULL, + NULL, + NULL, NULL, &battery_activate, &battery_deactivate); } diff --git a/modules/battery.cfg b/modules/battery.cfg index 683b3ee..c763872 100644 --- a/modules/battery.cfg +++ b/modules/battery.cfg @@ -1,10 +1,10 @@ [BATTERY] -menu_order = 50 +menu_order = 31 name = Battery Display default = true -help = Displays battery percentage +help = Displays battery percentage. [BATTERY_SHOW_VOLTAGE] name = Show voltage default = false -help = Besides battery percentage, also displays battery voltage \ No newline at end of file +help = Besides battery percentage, also displays battery voltage. \ No newline at end of file diff --git a/modules/boil.c b/modules/boil.c new file mode 100644 index 0000000..44456bc --- /dev/null +++ b/modules/boil.c @@ -0,0 +1,150 @@ +/** + modules/boil.c: boiling point calculator module for openchronos-ng + + Copyright (C) 2019 Luca Lorello + + http://github.com/HashakGik/openchronos-ng-elf + + This file is part of openchronos-ng. + + openchronos-ng 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. + + openchronos-ng 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 . +**/ + +/* This module uses the BMP085 sensor (white PCB) to calculate the boiling point of eight substances in the current environment, by using the Antoine equation [ https://en.wikipedia.org/wiki/Antoine_equation ]. + + The up and down keys change the substance (water is default). + The # key changes the displayed unit between celsius (default), farenheit, kelvin and rankine. + */ + +#include "messagebus.h" +#include "menu.h" +#include "config.h" + +#include "drivers/display.h" +#include "drivers/bmp_ps.h" +#include "drivers/ps.h" + +#include + +#define C_TO_K(x) (x + 273.15000) +#define C_TO_F(x) (x * 1.8 + 32000) +#define C_TO_R(x) (x * 1.8 + 491.67000) + +#define PA_TO_MMHG(x) (x / 133.32237) + +// Data taken from table B.4: https://onlinelibrary.wiley.com/doi/pdf/10.1002/9781118477304.app2 +#define SUB_NUM 8 +static float a[SUB_NUM] = +{ 8.01767, 8.07240, 8.11220, 6.90565, 6.99052, 6.95464, 6.93710, + 7.23160 }; +static float b[SUB_NUM] = +{ 1715.700000, 1574.99000, 1592.86400, 1211.03300, 1452.43000, 1344.80000, 1171.20000, + 1277.030 }; +static float c[SUB_NUM] = +{ 234.26800, 238.87000, 226.18400, 220.79000, 215.30700, 219.48200, 227.00000, + 237.23000 }; +static char substances[SUB_NUM][6] = +{ "WATER", "METHA", "ETHAN", "BENZE", "XYLEN", "TOLUE", "CLFOR", + "ACETO" }; + +static uint8_t i; +static uint8_t unit; +static uint8_t boil_counter; + +static void print_boil(void) +{ + float t = b[i] / (a[i] - log10f(PA_TO_MMHG(bmp_ps_get_pa()))) - c[i]; + + display_chars(0, LCD_SEG_L2_4_0, substances[i], SEG_SET); + display_symbol(0, LCD_UNIT_L1_DEGREE, SEG_SET); + switch (unit) { + case 0: // Celsius + display_char(0, LCD_SEG_L1_0, 'C', SEG_SET); + break; + case 1: // Farenheit + display_char(0, LCD_SEG_L1_0, 'F', SEG_SET); + t = C_TO_F(t); + break; + case 2: // Kelvin + display_char(0, LCD_SEG_L1_0, 'K', SEG_SET); + t = C_TO_K(t); + break; + case 3: // Rankine + display_char(0, LCD_SEG_L1_0, 'R', SEG_SET); + t = C_TO_R(t); + break; + } + + if ((int) t < 0) { + display_symbol(0, LCD_SYMB_ARROW_DOWN, SEG_SET); + t = -t; + } else + display_symbol(0, LCD_SYMB_ARROW_DOWN, SEG_OFF); + + + if ((uint16_t) t == 0) + display_chars(0, LCD_SEG_L1_3_1, " 0", SEG_SET); + else + _printf(0, LCD_SEG_L1_3_1, "%3u", (uint16_t) t); +} + +static void boil_interrupt(enum sys_message msg) +{ + if (boil_counter == 0) + print_boil(); + + boil_counter = (boil_counter + 1) % CONFIG_MOD_BOIL_REFRESH; +} + +static void up_btn(void) +{ + i = (i + 1) % SUB_NUM; + print_boil(); +} + +static void down_btn(void) +{ + i = (i + SUB_NUM - 1) % SUB_NUM; + print_boil(); +} + +static void num_pressed(void) +{ + unit = (unit + 1) % 4; + print_boil(); +} + +static void boil_activate(void) +{ + i = unit = boil_counter = 0; + bmp_ps_init(); + init_pressure_table(); + bmp_ps_start(); + + sys_messagebus_register(&boil_interrupt, SYS_MSG_RTC_SECOND); +} + +static void boil_deactivate(void) +{ + bmp_ps_stop(); + sys_messagebus_unregister_all(&boil_interrupt); + + display_clear(0, 0); +} + +void mod_boil_init(void) +{ + menu_add_entry("BOIL", &up_btn, &down_btn, &num_pressed, NULL, NULL, + NULL, &boil_activate, &boil_deactivate); +} diff --git a/modules/boil.cfg b/modules/boil.cfg new file mode 100644 index 0000000..981c85d --- /dev/null +++ b/modules/boil.cfg @@ -0,0 +1,13 @@ +[BOIL] +menu_order = 24 +name = Boiling point module +default = false +help = Calculates boiling point of water and other liquids at current pressure. +depends = WHITE_PCB + +[BOIL_REFRESH] +name = Boiling point module refresh rate +ifndef = true +type = text +default = 60 +help = Pressure update (in seconds) for boiling point calculation. \ No newline at end of file diff --git a/modules/buzztest.c b/modules/buzztest.c index 32d66df..85f53c7 100644 --- a/modules/buzztest.c +++ b/modules/buzztest.c @@ -1,24 +1,24 @@ /** - modules/buzztest.c: Buzzer test module for openchronos-ng + modules/buzztest.c: Buzzer test module for openchronos-ng - Copyright (C) 2017 Benjamin Sølberg + Copyright (C) 2017 Benjamin Sølberg - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ #include @@ -27,63 +27,64 @@ /* drivers */ #include "drivers/display.h" -static note n[2] = {0x3200, 0x000F}; +static note n[2] = { 0x3200, 0x000F }; + int8_t oct = 0; int8_t key = 1; -static void activate() { - /* update screen */ - display_chars(0, LCD_SEG_L2_4_1, "BUZZ", SEG_ON); +static void activate() +{ + /* update screen */ + display_chars(0, LCD_SEG_L2_4_1, "BUZZ", SEG_ON); } -static void deactivate() { - /* cleanup screen */ - display_clear(0, 2); +static void deactivate() +{ + /* cleanup screen */ + display_clear(0, 2); } -static void update() { - _printf(0, LCD_SEG_L1_3_2, "%02u", oct); - _printf(0, LCD_SEG_L1_1_0, "%02u", key); +static void update() +{ + _printf(0, LCD_SEG_L1_3_2, "%02u", oct); + _printf(0, LCD_SEG_L1_1_0, "%02u", key); - n[0] = 0x3200 + (oct << 4) + key; - buzzer_play(n); + n[0] = 0x3200 + (oct << 4) + key; + buzzer_play(n); } -static void up() { - key++; - if (key > 12) { - key = 1; +static void up() +{ + key++; + if (key > 12) { + key = 1; - oct++; - if (oct > 3) - oct = 0; - } + oct++; + if (oct > 3) + oct = 0; + } - update(); + update(); } -static void down() { - key--; - if (key <= 0) { - key = 12; - oct--; +static void down() +{ + key--; + if (key <= 0) { + key = 12; + oct--; - if (oct < 0) - oct = 3; - } + if (oct < 0) + oct = 3; + } - update(); + update(); } -void mod_buzztest_init(void) { - menu_add_entry("BUZZ", - &up, - &down, - NULL, - NULL, - NULL, - NULL, - &activate, - &deactivate); +void mod_buzztest_init(void) +{ + menu_add_entry("BUZZ", + &up, + &down, NULL, NULL, NULL, NULL, &activate, &deactivate); } diff --git a/modules/buzztest.cfg b/modules/buzztest.cfg index 3c28077..7526e47 100644 --- a/modules/buzztest.cfg +++ b/modules/buzztest.cfg @@ -1,4 +1,4 @@ [BUZZTEST] -menu_order = 99 +menu_order = 98 name = Buzzer test module [FOR TESTING] -help = Use up and down to play higher or lower notes \ No newline at end of file +help = Use up and down to play higher or lower notes. \ No newline at end of file diff --git a/modules/clock.c b/modules/clock.c index 58e79a6..3b1e8a1 100644 --- a/modules/clock.c +++ b/modules/clock.c @@ -1,25 +1,25 @@ /** - modules/clock.c: clock module for openchronos-ng + modules/clock.c: clock module for openchronos-ng - Copyright (C) 2012 Angelo Arrifano - Copyright (C) 2016 Benjamin Sølberg + Copyright (C) 2012 Angelo Arrifano + Copyright (C) 2016 Benjamin Sølberg - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ #include @@ -32,11 +32,11 @@ #include "drivers/display.h" #ifdef CONFIG_MOD_CLOCK_MONTH_FIRST - #define MONTH_SEGMENT (LCD_SEG_L2_4_3) - #define DAY_SEGMENT (LCD_SEG_L2_1_0) +#define MONTH_SEGMENT (LCD_SEG_L2_4_3) +#define DAY_SEGMENT (LCD_SEG_L2_1_0) #else - #define MONTH_SEGMENT (LCD_SEG_L2_1_0) - #define DAY_SEGMENT (LCD_SEG_L2_4_3) +#define MONTH_SEGMENT (LCD_SEG_L2_1_0) +#define DAY_SEGMENT (LCD_SEG_L2_4_3) #endif #define SECONDS_SEGMENT (LCD_SEG_L2_1_0) @@ -48,82 +48,85 @@ static uint8_t display_seconds = 0; static void clock_event(enum sys_message msg) { #ifdef CONFIG_MOD_CLOCK_BLINKCOL - if (msg & SYS_MSG_RTC_SECOND) { - display_symbol(0, LCD_SEG_L1_COL, ((datetime->sec & 0x01) ? SEG_ON : SEG_OFF)); - } + if (msg & SYS_MSG_RTC_SECOND) { + display_symbol(0, LCD_SEG_L1_COL, + ((datetime->sec & 0x01) ? SEG_ON : SEG_OFF)); + } #endif - if (display_seconds) { - if (msg & SYS_MSG_RTC_SECOND) { - _printf(0, SECONDS_SEGMENT, "%02u", datetime->sec); - } - } else { - if ((msg & SYS_MSG_RTC_DAY) || (msg & SYS_MSG_RTC_MONTH)) // Collapsed to simplify code path - { - _printf(0, MONTH_SEGMENT, "%02u", datetime->mon); - _printf(0, DAY_SEGMENT, "%02u", datetime->day); - display_char (0, LCD_SEG_L2_2, '-', SEG_SET); - } - } - - if (msg & SYS_MSG_RTC_DAY) - _printf(1, LCD_SEG_L2_2_0, rtca_dow_str[datetime->dow], SEG_SET); - - if (msg & SYS_MSG_RTC_YEAR) - _printf(1, LCD_SEG_L1_3_0, "%04u", datetime->year); - - if (msg & SYS_MSG_RTC_HOUR) { - if (display_am_pm) { - uint8_t tmp_hh = datetime->hour; - if (tmp_hh > 12) { //PM - tmp_hh -= 12; - display_symbol(0, LCD_SYMB_PM, SEG_SET); - } else { - if (tmp_hh == 12) { // PM - display_symbol(0, LCD_SYMB_PM, SEG_SET); - } else { // AM - display_symbol(0, LCD_SYMB_PM, SEG_OFF); - } - if (tmp_hh == 0) - tmp_hh = 12; - } - _printf(0, LCD_SEG_L1_3_2, "%2u", tmp_hh); - } else { - _printf(0, LCD_SEG_L1_3_2, "%02u", datetime->hour); - display_symbol(0, LCD_SYMB_PM, SEG_OFF); - } - } - if (msg & SYS_MSG_RTC_MINUTE) - _printf(0, LCD_SEG_L1_1_0, "%02u", datetime->min); + if (display_seconds) { + if (msg & SYS_MSG_RTC_SECOND) { + _printf(0, SECONDS_SEGMENT, "%02u", datetime->sec); + } + } else { + if ((msg & SYS_MSG_RTC_DAY) || (msg & SYS_MSG_RTC_MONTH)) // Collapsed to simplify code path + { + _printf(0, MONTH_SEGMENT, "%02u", datetime->mon); + _printf(0, DAY_SEGMENT, "%02u", datetime->day); + display_char(0, LCD_SEG_L2_2, '-', SEG_SET); + } + } + + if (msg & SYS_MSG_RTC_DAY) + _printf(1, LCD_SEG_L2_2_0, rtca_dow_str[datetime->dow], SEG_SET); + + if (msg & SYS_MSG_RTC_YEAR) + _printf(1, LCD_SEG_L1_3_0, "%04u", datetime->year); + + if (msg & SYS_MSG_RTC_HOUR) { + if (display_am_pm) { + uint8_t tmp_hh = datetime->hour; + if (tmp_hh > 12) { //PM + tmp_hh -= 12; + display_symbol(0, LCD_SYMB_PM, SEG_SET); + } else { + if (tmp_hh == 12) { // PM + display_symbol(0, LCD_SYMB_PM, SEG_SET); + } else { // AM + display_symbol(0, LCD_SYMB_PM, SEG_OFF); + } + if (tmp_hh == 0) + tmp_hh = 12; + } + _printf(0, LCD_SEG_L1_3_2, "%2u", tmp_hh); + } else { + _printf(0, LCD_SEG_L1_3_2, "%02u", datetime->hour); + display_symbol(0, LCD_SYMB_PM, SEG_OFF); + } + } + if (msg & SYS_MSG_RTC_MINUTE) + _printf(0, LCD_SEG_L1_1_0, "%02u", datetime->min); } /* update screens with fake event */ static inline void update_screen() { - clock_event(SYS_MSG_RTC_YEAR | SYS_MSG_RTC_MONTH | SYS_MSG_RTC_DAY | - SYS_MSG_RTC_HOUR | SYS_MSG_RTC_MINUTE | SYS_MSG_RTC_SECOND); + clock_event(SYS_MSG_RTC_YEAR | SYS_MSG_RTC_MONTH | SYS_MSG_RTC_DAY | + SYS_MSG_RTC_HOUR | SYS_MSG_RTC_MINUTE | + SYS_MSG_RTC_SECOND); } /* In effect when adjusting from one month to another month with less days and the day needs to be adjusted, This effect can also be seen when changing from leap year to non leap year and the date is 02-29 */ static void auto_adjust_dd() { - uint8_t min_day = rtca_get_max_days(datetime->mon, datetime->year); - if (min_day < datetime->day) { - datetime->day = min_day; - update_screen(); - } + uint8_t min_day = rtca_get_max_days(datetime->mon, datetime->year); + if (min_day < datetime->day) { + datetime->day = min_day; + update_screen(); + } } -static void register_events() { - sys_messagebus_register(&clock_event, - SYS_MSG_RTC_YEAR | SYS_MSG_RTC_MONTH | SYS_MSG_RTC_DAY | - SYS_MSG_RTC_HOUR | SYS_MSG_RTC_MINUTE | SYS_MSG_RTC_SECOND - ); +static void register_events() +{ + sys_messagebus_register(&clock_event, + SYS_MSG_RTC_YEAR | SYS_MSG_RTC_MONTH | + SYS_MSG_RTC_DAY | SYS_MSG_RTC_HOUR | + SYS_MSG_RTC_MINUTE | SYS_MSG_RTC_SECOND); } static void unregister_events() { - sys_messagebus_unregister_all(&clock_event); + sys_messagebus_unregister_all(&clock_event); } /********************* edit mode callbacks ********************************/ @@ -131,268 +134,271 @@ static void unregister_events() /* Year */ static void edit_yy_sel(void) { - lcd_screen_activate(1); - display_chars(1, LCD_SEG_L1_3_0, NULL, BLINK_ON); + lcd_screen_activate(1); + display_chars(1, LCD_SEG_L1_3_0, NULL, BLINK_ON); } static void edit_yy_dsel(void) { - display_chars(1, LCD_SEG_L1_3_0, NULL, BLINK_OFF); + display_chars(1, LCD_SEG_L1_3_0, NULL, BLINK_OFF); } static void edit_yy_set(int8_t step) { - /* this allows setting years between 2012 and 2047 */ - // 0x07DC = 2012 and 0x07FF = 2047 - // The helpers_loop will only handle the low byte - *((uint8_t *)&datetime->year + 1) = 0x07; - helpers_loop((uint8_t *)&datetime->year, 0xDC, 0xFF, step); + /* this allows setting years between 2012 and 2047 */ + // 0x07DC = 2012 and 0x07FF = 2047 + // The helpers_loop will only handle the low byte + *((uint8_t *) & datetime->year + 1) = 0x07; + helpers_loop((uint8_t *) & datetime->year, 0xDC, 0xFF, step); - auto_adjust_dd(); - rtca_update_dow(datetime); - update_screen(); + auto_adjust_dd(); + rtca_update_dow(datetime); + update_screen(); } /* Month */ static void edit_mo_sel(void) { - lcd_screen_activate(0); - display_chars(0, MONTH_SEGMENT, NULL, BLINK_ON); + lcd_screen_activate(0); + display_chars(0, MONTH_SEGMENT, NULL, BLINK_ON); } static void edit_mo_dsel(void) { - display_chars(0, MONTH_SEGMENT, NULL, BLINK_OFF); + display_chars(0, MONTH_SEGMENT, NULL, BLINK_OFF); } static void edit_mo_set(int8_t step) { - helpers_loop(&datetime->mon, 1, 12, step); + helpers_loop(&datetime->mon, 1, 12, step); - auto_adjust_dd(); - rtca_update_dow(datetime); - update_screen(); + auto_adjust_dd(); + rtca_update_dow(datetime); + update_screen(); } /* Day */ static void edit_dd_sel(void) { - lcd_screen_activate(0); - display_chars(0, DAY_SEGMENT, NULL, BLINK_ON); + lcd_screen_activate(0); + display_chars(0, DAY_SEGMENT, NULL, BLINK_ON); } static void edit_dd_dsel(void) { - display_chars(0, DAY_SEGMENT, NULL, BLINK_OFF); + display_chars(0, DAY_SEGMENT, NULL, BLINK_OFF); } static void edit_dd_set(int8_t step) { - helpers_loop(&datetime->day, 1, rtca_get_max_days(datetime->mon, - datetime->year), step); - rtca_update_dow(datetime); - update_screen(); + helpers_loop(&datetime->day, 1, rtca_get_max_days(datetime->mon, + datetime->year), + step); + rtca_update_dow(datetime); + update_screen(); } /* Hour */ static void edit_hh_sel(void) { - lcd_screen_activate(0); - display_chars(0, LCD_SEG_L1_3_2, NULL, BLINK_ON); + lcd_screen_activate(0); + display_chars(0, LCD_SEG_L1_3_2, NULL, BLINK_ON); } + static void edit_hh_dsel(void) { - display_chars(0, LCD_SEG_L1_3_2, NULL, BLINK_OFF); + display_chars(0, LCD_SEG_L1_3_2, NULL, BLINK_OFF); } + static void edit_hh_set(int8_t step) { - helpers_loop(&datetime->hour, 0, 23, step); - update_screen(); + helpers_loop(&datetime->hour, 0, 23, step); + update_screen(); } /* Minute */ static void edit_mm_sel(void) { - lcd_screen_activate(0); - display_chars(0, LCD_SEG_L1_1_0, NULL, BLINK_ON); + lcd_screen_activate(0); + display_chars(0, LCD_SEG_L1_1_0, NULL, BLINK_ON); } static void edit_mm_dsel(void) { - display_chars(0, LCD_SEG_L1_1_0, NULL, BLINK_OFF); + display_chars(0, LCD_SEG_L1_1_0, NULL, BLINK_OFF); } static void edit_mm_set(int8_t step) { - helpers_loop(&datetime->min, 0, 59, step); - update_screen(); + helpers_loop(&datetime->min, 0, 59, step); + update_screen(); } /* 12h/24h */ static void edit_12_24_display(void) { - display_chars(2, LCD_SEG_L1_3_0 , display_am_pm ? " 12H" : " 24H", SEG_SET); + display_chars(2, LCD_SEG_L1_3_0, display_am_pm ? " 12H" : " 24H", + SEG_SET); } static void edit_12_24_sel(void) { - lcd_screen_activate(2); - edit_12_24_display(); - display_chars(2, LCD_SEG_L1_3_0, NULL, BLINK_ON); + lcd_screen_activate(2); + edit_12_24_display(); + display_chars(2, LCD_SEG_L1_3_0, NULL, BLINK_ON); } static void edit_12_24_dsel(void) { - display_chars(2, LCD_SEG_L1_3_0, NULL, BLINK_OFF); + display_chars(2, LCD_SEG_L1_3_0, NULL, BLINK_OFF); } static void edit_12_24_set(int8_t step) { - display_am_pm ^= 1; - edit_12_24_display(); - update_screen(); + display_am_pm ^= 1; + edit_12_24_display(); + update_screen(); } -static void edit_end() {/* turn off only SOME blinking segments */ - display_chars(0, LCD_SEG_L1_3_0, NULL, BLINK_OFF); - display_chars(0, LCD_SEG_L2_4_0, NULL, BLINK_OFF); - display_chars(1, LCD_SEG_L1_3_0, NULL, BLINK_OFF); - display_chars(2, LCD_SEG_L1_3_0, NULL, BLINK_OFF); +static void edit_end() +{ /* turn off only SOME blinking segments */ + display_chars(0, LCD_SEG_L1_3_0, NULL, BLINK_OFF); + display_chars(0, LCD_SEG_L2_4_0, NULL, BLINK_OFF); + display_chars(1, LCD_SEG_L1_3_0, NULL, BLINK_OFF); + display_chars(2, LCD_SEG_L1_3_0, NULL, BLINK_OFF); - /* return to main screen */ - lcd_screen_activate(0); + /* return to main screen */ + lcd_screen_activate(0); - /* update screens with fake event */ - update_screen(); + /* update screens with fake event */ + update_screen(); - register_events(); + register_events(); - rtca_start(); + rtca_start(); } static void edit_cancel() { - rtca_stop(); // Countered in edit_end + rtca_stop(); // Countered in edit_end - free(datetime); - datetime = &rtca_time; // Restore current time - edit_end(); + free(datetime); + datetime = &rtca_time; // Restore current time + edit_end(); } /* Save YMDHMS */ static void edit_save() { - rtca_stop(); // Countered in rtca_set_time and rtca_set_date and edit_end + rtca_stop(); // Countered in rtca_set_time and rtca_set_date and edit_end - /* Here we return from the edit mode, fill in the new values! */ - uint32_t sys_clocks = rtca_time.sys; - memcpy(&rtca_time, datetime, sizeof(struct DATETIME)); - rtca_time.sys = sys_clocks; - free(datetime); - datetime = &rtca_time; + /* Here we return from the edit mode, fill in the new values! */ + uint32_t sys_clocks = rtca_time.sys; + memcpy(&rtca_time, datetime, sizeof(struct DATETIME)); + rtca_time.sys = sys_clocks; + free(datetime); + datetime = &rtca_time; - datetime->sec = 0; - rtca_set_time(); - rtca_set_date(); - edit_end(); + datetime->sec = 0; + rtca_set_time(); + rtca_set_date(); + edit_end(); } /* edit mode item table */ static struct menu_editmode_item edit_items[] = { - {&edit_hh_sel, &edit_hh_dsel, &edit_hh_set}, - {&edit_mm_sel, &edit_mm_dsel, &edit_mm_set}, - {&edit_yy_sel, &edit_yy_dsel, &edit_yy_set}, - {&edit_mo_sel, &edit_mo_dsel, &edit_mo_set}, - {&edit_dd_sel, &edit_dd_dsel, &edit_dd_set}, - {&edit_12_24_sel, &edit_12_24_dsel, &edit_12_24_set}, - { NULL }, + {&edit_hh_sel, &edit_hh_dsel, &edit_hh_set}, + {&edit_mm_sel, &edit_mm_dsel, &edit_mm_set}, + {&edit_yy_sel, &edit_yy_dsel, &edit_yy_set}, + {&edit_mo_sel, &edit_mo_dsel, &edit_mo_set}, + {&edit_dd_sel, &edit_dd_dsel, &edit_dd_set}, + {&edit_12_24_sel, &edit_12_24_dsel, &edit_12_24_set}, + {NULL}, }; static void edit_activate() { - rtca_stop(); + rtca_stop(); - unregister_events(); + unregister_events(); - struct DATETIME *edit_rtca = (struct DATETIME *) malloc(sizeof(struct DATETIME)); - memcpy(edit_rtca, datetime, sizeof(struct DATETIME)); - datetime = edit_rtca; + struct DATETIME *edit_rtca = + (struct DATETIME *) malloc(sizeof(struct DATETIME)); + memcpy(edit_rtca, datetime, sizeof(struct DATETIME)); + datetime = edit_rtca; - rtca_start(); + rtca_start(); #ifdef CONFIG_MOD_CLOCK_BLINKCOL - /* the blinking dots feature might hide the two dots, we display them here just in case */ + /* the blinking dots feature might hide the two dots, we display them here just in case */ #endif - display_seconds = 0; - update_screen(); - display_symbol(0, LCD_SEG_L1_COL, SEG_ON); - menu_editmode_start(&edit_save, &edit_cancel, edit_items); + display_seconds = 0; + update_screen(); + display_symbol(0, LCD_SEG_L1_COL, SEG_ON); + menu_editmode_start(&edit_save, &edit_cancel, edit_items); } /************************ menu callbacks **********************************/ static void clock_activated() { - register_events(); + register_events(); - /* create three screens, the first is always the active one */ - lcd_screens_create(3); // 0:time + date, 1: year + day of week, 2:temp for settings (ex 12/24h setup) + /* create three screens, the first is always the active one */ + lcd_screens_create(3); // 0:time + date, 1: year + day of week, 2:temp for settings (ex 12/24h setup) - display_symbol(0, LCD_SEG_L1_COL, SEG_ON); + display_symbol(0, LCD_SEG_L1_COL, SEG_ON); - /* update screens with fake event */ - update_screen(); + /* update screens with fake event */ + update_screen(); } static void clock_deactivated() { - unregister_events(); + unregister_events(); - /* destroy virtual screens */ - lcd_screens_destroy(); + /* destroy virtual screens */ + lcd_screens_destroy(); - /* clean up screen */ - display_symbol(0, LCD_SEG_L1_COL, SEG_OFF); - display_symbol(0, LCD_SYMB_PM, SEG_OFF); + /* clean up screen */ + display_symbol(0, LCD_SEG_L1_COL, SEG_OFF); + display_symbol(0, LCD_SYMB_PM, SEG_OFF); - display_clear(0, 1); - display_clear(0, 2); + display_clear(0, 1); + display_clear(0, 2); } /* Num button press callback */ static void num_pressed() { - uint8_t index = get_active_lcd_screen_nr(); - if (++index >= 2) { - index = 0; // Skip setup screen - } + uint8_t index = get_active_lcd_screen_nr(); + if (++index >= 2) { + index = 0; // Skip setup screen + } - lcd_screen_activate(index); + lcd_screen_activate(index); } /* Star button long press callback. */ static void star_long_pressed() { - edit_activate(); + edit_activate(); } static void up_down_pressed() { - display_seconds ^= 1; - display_clear(0, 2); + display_seconds ^= 1; + display_clear(0, 2); - update_screen(); + update_screen(); } void mod_clock_init() { - menu_add_entry("CLOCK", - &up_down_pressed, - &up_down_pressed, - &num_pressed, - &star_long_pressed, - NULL, - NULL, - &clock_activated, - &clock_deactivated); + menu_add_entry("CLOCK", + &up_down_pressed, + &up_down_pressed, + &num_pressed, + &star_long_pressed, + NULL, NULL, &clock_activated, &clock_deactivated); } diff --git a/modules/clock.cfg b/modules/clock.cfg index c9d4cfa..607894c 100644 --- a/modules/clock.cfg +++ b/modules/clock.cfg @@ -1,21 +1,21 @@ [CLOCK] -menu_order = 10 +menu_order = 1 name = Clock default = true depends = CONFIG_RTC_IRQ -help = Shows current time +help = Shows current time. [CLOCK_BLINKCOL] name = Blinking colon default = true -help = Blink colon to let you know the clock is running +help = Blink colon to let you know the clock is running. [CLOCK_AMPM] name = AM PM Time default = false -help = Display time in 12-hour format +help = Display time in 12-hour format. [CLOCK_MONTH_FIRST] name = Display month first default = false -help = Display date in MM-DD instead of DD-MM +help = Display date in MM-DD instead of DD-MM. diff --git a/modules/crickets.c b/modules/crickets.c new file mode 100644 index 0000000..fb0b363 --- /dev/null +++ b/modules/crickets.c @@ -0,0 +1,109 @@ +/** + modules/crickets.c: cricket's chirp calculator module for openchronos-ng + + Copyright (C) 2019 Luca Lorello + + http://github.com/HashakGik/openchronos-ng-elf + + This file is part of openchronos-ng. + + openchronos-ng 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. + + openchronos-ng 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 . +**/ + +/* This module calculates the number of cricket's chirp at the current temperature by using [ https://en.wikipedia.org/wiki/Dolbear's_law ] + The original formula was meant to be used as a temperature estimate based on chirp count (of a very specific species of cricket), so the inverse formula might not be precise. + + The # key changes the displayed unit between chirps per minute (default), chirps per hour and chirps per second. + */ + +#include "messagebus.h" +#include "menu.h" +#include "config.h" + +#include "drivers/display.h" +#include "drivers/temperature.h" + +static uint8_t i; +static uint8_t unit; + +static void display_chirp(void) +{ + int16_t t; + int16_t freq; + + temperature_get_C(&t); + freq = 7 * (t / 10 - 10) + 40; // t is in tenth of C. + + switch (unit) { + case 0: // per minute + display_symbol(0, LCD_UNIT_L1_M, SEG_SET); + display_symbol(0, LCD_UNIT_L1_I, SEG_SET); + display_symbol(0, LCD_UNIT_L1_PER_S, SEG_OFF); + display_symbol(0, LCD_UNIT_L1_PER_H, SEG_OFF); + break; + case 1: // per hour + freq *= 60; + display_symbol(0, LCD_UNIT_L1_M, SEG_OFF); + display_symbol(0, LCD_UNIT_L1_I, SEG_OFF); + display_symbol(0, LCD_UNIT_L1_PER_S, SEG_OFF); + display_symbol(0, LCD_UNIT_L1_PER_H, SEG_SET); + break; + case 2: // per second + freq /= 60; + display_symbol(0, LCD_UNIT_L1_M, SEG_OFF); + display_symbol(0, LCD_UNIT_L1_I, SEG_OFF); + display_symbol(0, LCD_UNIT_L1_PER_S, SEG_SET); + display_symbol(0, LCD_UNIT_L1_PER_H, SEG_OFF); + break; + } + + if (freq > 0) + _printf(0, LCD_SEG_L1_3_0, "%4u", freq); + else + display_chars(0, LCD_SEG_L1_3_0, " 0", SEG_SET); +} + +static void chirp_interrupt(enum sys_message msg) +{ + if (i == 0) { + display_chirp(); + } + + i = (i + 1) % CONFIG_MOD_CRICKETS_REFRESH; +} + +static void change_unit(void) +{ + unit = (unit + 1) % 3; + display_chirp(); +} + +static void crickets_activate(void) +{ + i = unit = 0; + sys_messagebus_register(&chirp_interrupt, SYS_MSG_RTC_SECOND); +} + +static void crickets_deactivate(void) +{ + sys_messagebus_unregister_all(&chirp_interrupt); + display_clear(0, 0); +} + + +void mod_crickets_init(void) +{ + menu_add_entry("CRICK", NULL, NULL, &change_unit, NULL, NULL, NULL, + &crickets_activate, &crickets_deactivate); +} diff --git a/modules/crickets.cfg b/modules/crickets.cfg new file mode 100644 index 0000000..a09a41d --- /dev/null +++ b/modules/crickets.cfg @@ -0,0 +1,12 @@ +[CRICKETS] +menu_order = 33 +name = Cricket's chirp frequency calculator +default = false +help = Calculates the number of cricket's chirps at the current temperature. + +[CRICKETS_REFRESH] +name = Cricket calculator refresh rate +ifndef = true +type = text +default = 60 +help = Refresh rate (in seconds) for chirp calculator. \ No newline at end of file diff --git a/modules/hashutils.c b/modules/hashutils.c index a82b090..2186372 100644 --- a/modules/hashutils.c +++ b/modules/hashutils.c @@ -39,11 +39,11 @@ * This code is in the public domain * ***************************************************************************** -*/ + */ #define _BSD_SOURCE #define _DEFAULT_SOURCE -#include // Defines BYTE_ORDER, iff _BSD_SOURCE is defined +#include // Defines BYTE_ORDER, iff _BSD_SOURCE is defined #include #include "hashutils.h" @@ -71,219 +71,230 @@ #define R32(x,n) T32(((x << n) | (x >> (32 - n)))) /* the generic case, for when the overall rotation is not unraveled */ -#define FG(n) \ - T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n); \ - E = D; D = C; C = R32(B,30); B = A; A = T +#define FG(n) \ + T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n); \ + E = D; D = C; C = R32(B,30); B = A; A = T -static void sha1_transform(SHA1_INFO *sha1_info) +static void sha1_transform(SHA1_INFO * sha1_info) { - int i; - uint8_t *dp; - uint32_t T, A, B, C, D, E, W[80], *WP; - - dp = sha1_info->data; - - for (i = 0; i < 16; ++i) { - T = *((uint32_t *) dp); - dp += 4; - W[i] = - ((T << 24) & 0xff000000) | - ((T << 8) & 0x00ff0000) | - ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); - } - - for (i = 16; i < 80; ++i) { - W[i] = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]; - W[i] = R32(W[i], 1); - } - A = sha1_info->digest[0]; - B = sha1_info->digest[1]; - C = sha1_info->digest[2]; - D = sha1_info->digest[3]; - E = sha1_info->digest[4]; - WP = W; - - for (i = 0; i < 20; ++i) { FG(1); } - for (i = 20; i < 40; ++i) { FG(2); } - for (i = 40; i < 60; ++i) { FG(3); } - for (i = 60; i < 80; ++i) { FG(4); } - sha1_info->digest[0] = T32(sha1_info->digest[0] + A); - sha1_info->digest[1] = T32(sha1_info->digest[1] + B); - sha1_info->digest[2] = T32(sha1_info->digest[2] + C); - sha1_info->digest[3] = T32(sha1_info->digest[3] + D); - sha1_info->digest[4] = T32(sha1_info->digest[4] + E); + int i; + uint8_t *dp; + uint32_t T, A, B, C, D, E, W[80], *WP; + + dp = sha1_info->data; + + for (i = 0; i < 16; ++i) { + T = *((uint32_t *) dp); + dp += 4; + W[i] = + ((T << 24) & 0xff000000) | + ((T << 8) & 0x00ff0000) | + ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); + } + + for (i = 16; i < 80; ++i) { + W[i] = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]; + W[i] = R32(W[i], 1); + } + A = sha1_info->digest[0]; + B = sha1_info->digest[1]; + C = sha1_info->digest[2]; + D = sha1_info->digest[3]; + E = sha1_info->digest[4]; + WP = W; + + for (i = 0; i < 20; ++i) { + FG(1); + } + for (i = 20; i < 40; ++i) { + FG(2); + } + for (i = 40; i < 60; ++i) { + FG(3); + } + for (i = 60; i < 80; ++i) { + FG(4); + } + sha1_info->digest[0] = T32(sha1_info->digest[0] + A); + sha1_info->digest[1] = T32(sha1_info->digest[1] + B); + sha1_info->digest[2] = T32(sha1_info->digest[2] + C); + sha1_info->digest[3] = T32(sha1_info->digest[3] + D); + sha1_info->digest[4] = T32(sha1_info->digest[4] + E); } /* initialize the SHA digest */ -void sha1_init(SHA1_INFO *sha1_info) +void sha1_init(SHA1_INFO * sha1_info) { - sha1_info->digest[0] = 0x67452301L; - sha1_info->digest[1] = 0xefcdab89L; - sha1_info->digest[2] = 0x98badcfeL; - sha1_info->digest[3] = 0x10325476L; - sha1_info->digest[4] = 0xc3d2e1f0L; - sha1_info->count_lo = 0L; - sha1_info->count_hi = 0L; - sha1_info->local = 0; + sha1_info->digest[0] = 0x67452301L; + sha1_info->digest[1] = 0xefcdab89L; + sha1_info->digest[2] = 0x98badcfeL; + sha1_info->digest[3] = 0x10325476L; + sha1_info->digest[4] = 0xc3d2e1f0L; + sha1_info->count_lo = 0L; + sha1_info->count_hi = 0L; + sha1_info->local = 0; } /* update the SHA digest */ -void sha1_update(SHA1_INFO *sha1_info, const uint8_t *buffer, int count) +void sha1_update(SHA1_INFO * sha1_info, const uint8_t * buffer, int count) { - int i; - uint32_t clo; - - clo = T32(sha1_info->count_lo + ((uint32_t) count << 3)); - if (clo < sha1_info->count_lo) { - ++sha1_info->count_hi; - } - sha1_info->count_lo = clo; - sha1_info->count_hi += (uint32_t) count >> 29; - if (sha1_info->local) { - i = SHA1_BLOCKSIZE - sha1_info->local; - if (i > count) { - i = count; - } - memcpy(((uint8_t *) sha1_info->data) + sha1_info->local, buffer, i); - count -= i; - buffer += i; - sha1_info->local += i; - if (sha1_info->local == SHA1_BLOCKSIZE) { - sha1_transform(sha1_info); - } else { - return; - } - } - while (count >= SHA1_BLOCKSIZE) { - memcpy(sha1_info->data, buffer, SHA1_BLOCKSIZE); - buffer += SHA1_BLOCKSIZE; - count -= SHA1_BLOCKSIZE; - sha1_transform(sha1_info); - } - memcpy(sha1_info->data, buffer, count); - sha1_info->local = count; + int i; + uint32_t clo; + + clo = T32(sha1_info->count_lo + ((uint32_t) count << 3)); + if (clo < sha1_info->count_lo) { + ++sha1_info->count_hi; + } + sha1_info->count_lo = clo; + sha1_info->count_hi += (uint32_t) count >> 29; + if (sha1_info->local) { + i = SHA1_BLOCKSIZE - sha1_info->local; + if (i > count) { + i = count; + } + memcpy(((uint8_t *) sha1_info->data) + sha1_info->local, buffer, + i); + count -= i; + buffer += i; + sha1_info->local += i; + if (sha1_info->local == SHA1_BLOCKSIZE) { + sha1_transform(sha1_info); + } else { + return; + } + } + while (count >= SHA1_BLOCKSIZE) { + memcpy(sha1_info->data, buffer, SHA1_BLOCKSIZE); + buffer += SHA1_BLOCKSIZE; + count -= SHA1_BLOCKSIZE; + sha1_transform(sha1_info); + } + memcpy(sha1_info->data, buffer, count); + sha1_info->local = count; } -static void sha1_transform_and_copy(unsigned char digest[20], SHA1_INFO *sha1_info) +static void sha1_transform_and_copy(unsigned char digest[20], + SHA1_INFO * sha1_info) { - sha1_transform(sha1_info); - digest[ 0] = (unsigned char) ((sha1_info->digest[0] >> 24) & 0xff); - digest[ 1] = (unsigned char) ((sha1_info->digest[0] >> 16) & 0xff); - digest[ 2] = (unsigned char) ((sha1_info->digest[0] >> 8) & 0xff); - digest[ 3] = (unsigned char) ((sha1_info->digest[0] ) & 0xff); - digest[ 4] = (unsigned char) ((sha1_info->digest[1] >> 24) & 0xff); - digest[ 5] = (unsigned char) ((sha1_info->digest[1] >> 16) & 0xff); - digest[ 6] = (unsigned char) ((sha1_info->digest[1] >> 8) & 0xff); - digest[ 7] = (unsigned char) ((sha1_info->digest[1] ) & 0xff); - digest[ 8] = (unsigned char) ((sha1_info->digest[2] >> 24) & 0xff); - digest[ 9] = (unsigned char) ((sha1_info->digest[2] >> 16) & 0xff); - digest[10] = (unsigned char) ((sha1_info->digest[2] >> 8) & 0xff); - digest[11] = (unsigned char) ((sha1_info->digest[2] ) & 0xff); - digest[12] = (unsigned char) ((sha1_info->digest[3] >> 24) & 0xff); - digest[13] = (unsigned char) ((sha1_info->digest[3] >> 16) & 0xff); - digest[14] = (unsigned char) ((sha1_info->digest[3] >> 8) & 0xff); - digest[15] = (unsigned char) ((sha1_info->digest[3] ) & 0xff); - digest[16] = (unsigned char) ((sha1_info->digest[4] >> 24) & 0xff); - digest[17] = (unsigned char) ((sha1_info->digest[4] >> 16) & 0xff); - digest[18] = (unsigned char) ((sha1_info->digest[4] >> 8) & 0xff); - digest[19] = (unsigned char) ((sha1_info->digest[4] ) & 0xff); + sha1_transform(sha1_info); + digest[0] = (unsigned char) ((sha1_info->digest[0] >> 24) & 0xff); + digest[1] = (unsigned char) ((sha1_info->digest[0] >> 16) & 0xff); + digest[2] = (unsigned char) ((sha1_info->digest[0] >> 8) & 0xff); + digest[3] = (unsigned char) ((sha1_info->digest[0]) & 0xff); + digest[4] = (unsigned char) ((sha1_info->digest[1] >> 24) & 0xff); + digest[5] = (unsigned char) ((sha1_info->digest[1] >> 16) & 0xff); + digest[6] = (unsigned char) ((sha1_info->digest[1] >> 8) & 0xff); + digest[7] = (unsigned char) ((sha1_info->digest[1]) & 0xff); + digest[8] = (unsigned char) ((sha1_info->digest[2] >> 24) & 0xff); + digest[9] = (unsigned char) ((sha1_info->digest[2] >> 16) & 0xff); + digest[10] = (unsigned char) ((sha1_info->digest[2] >> 8) & 0xff); + digest[11] = (unsigned char) ((sha1_info->digest[2]) & 0xff); + digest[12] = (unsigned char) ((sha1_info->digest[3] >> 24) & 0xff); + digest[13] = (unsigned char) ((sha1_info->digest[3] >> 16) & 0xff); + digest[14] = (unsigned char) ((sha1_info->digest[3] >> 8) & 0xff); + digest[15] = (unsigned char) ((sha1_info->digest[3]) & 0xff); + digest[16] = (unsigned char) ((sha1_info->digest[4] >> 24) & 0xff); + digest[17] = (unsigned char) ((sha1_info->digest[4] >> 16) & 0xff); + digest[18] = (unsigned char) ((sha1_info->digest[4] >> 8) & 0xff); + digest[19] = (unsigned char) ((sha1_info->digest[4]) & 0xff); } /* finish computing the SHA digest */ -void sha1_final(SHA1_INFO *sha1_info, uint8_t digest[20]) +void sha1_final(SHA1_INFO * sha1_info, uint8_t digest[20]) { - int count; - uint32_t lo_bit_count, hi_bit_count; - - lo_bit_count = sha1_info->count_lo; - hi_bit_count = sha1_info->count_hi; - count = (int) ((lo_bit_count >> 3) & 0x3f); - ((uint8_t *) sha1_info->data)[count++] = 0x80; - if (count > SHA1_BLOCKSIZE - 8) { - memset(((uint8_t *) sha1_info->data) + count, 0, SHA1_BLOCKSIZE - count); - sha1_transform(sha1_info); - memset((uint8_t *) sha1_info->data, 0, SHA1_BLOCKSIZE - 8); - } else { - memset(((uint8_t *) sha1_info->data) + count, 0, - SHA1_BLOCKSIZE - 8 - count); - } - sha1_info->data[56] = (uint8_t)((hi_bit_count >> 24) & 0xff); - sha1_info->data[57] = (uint8_t)((hi_bit_count >> 16) & 0xff); - sha1_info->data[58] = (uint8_t)((hi_bit_count >> 8) & 0xff); - sha1_info->data[59] = (uint8_t)((hi_bit_count >> 0) & 0xff); - sha1_info->data[60] = (uint8_t)((lo_bit_count >> 24) & 0xff); - sha1_info->data[61] = (uint8_t)((lo_bit_count >> 16) & 0xff); - sha1_info->data[62] = (uint8_t)((lo_bit_count >> 8) & 0xff); - sha1_info->data[63] = (uint8_t)((lo_bit_count >> 0) & 0xff); - sha1_transform_and_copy(digest, sha1_info); + int count; + uint32_t lo_bit_count, hi_bit_count; + + lo_bit_count = sha1_info->count_lo; + hi_bit_count = sha1_info->count_hi; + count = (int) ((lo_bit_count >> 3) & 0x3f); + ((uint8_t *) sha1_info->data)[count++] = 0x80; + if (count > SHA1_BLOCKSIZE - 8) { + memset(((uint8_t *) sha1_info->data) + count, 0, + SHA1_BLOCKSIZE - count); + sha1_transform(sha1_info); + memset((uint8_t *) sha1_info->data, 0, SHA1_BLOCKSIZE - 8); + } else { + memset(((uint8_t *) sha1_info->data) + count, 0, + SHA1_BLOCKSIZE - 8 - count); + } + sha1_info->data[56] = (uint8_t) ((hi_bit_count >> 24) & 0xff); + sha1_info->data[57] = (uint8_t) ((hi_bit_count >> 16) & 0xff); + sha1_info->data[58] = (uint8_t) ((hi_bit_count >> 8) & 0xff); + sha1_info->data[59] = (uint8_t) ((hi_bit_count >> 0) & 0xff); + sha1_info->data[60] = (uint8_t) ((lo_bit_count >> 24) & 0xff); + sha1_info->data[61] = (uint8_t) ((lo_bit_count >> 16) & 0xff); + sha1_info->data[62] = (uint8_t) ((lo_bit_count >> 8) & 0xff); + sha1_info->data[63] = (uint8_t) ((lo_bit_count >> 0) & 0xff); + sha1_transform_and_copy(digest, sha1_info); } -/*---------------------HMAC_SHA1-------------------------*/ +/*---------------------HMAC_SHA1-------------------------*/ uint8_t tmp_key[64]; uint8_t sha[SHA1_DIGEST_LENGTH]; uint8_t hashed_key[SHA1_DIGEST_LENGTH]; -void hmac_sha1(const uint8_t *key, int keyLength, - const uint8_t *data, int dataLength, - uint8_t *result, int resultLength) { - SHA1_INFO ctx; - int i; - // Zero out all internal data structures - memset(hashed_key, 0, sizeof(hashed_key)); - memset(sha, 0, sizeof(sha)); - memset(tmp_key, 0, sizeof(tmp_key)); +void hmac_sha1(const uint8_t * key, int keyLength, + const uint8_t * data, int dataLength, + uint8_t * result, int resultLength) +{ + SHA1_INFO ctx; + int i; + // Zero out all internal data structures + memset(hashed_key, 0, sizeof(hashed_key)); + memset(sha, 0, sizeof(sha)); + memset(tmp_key, 0, sizeof(tmp_key)); - memset(&ctx, 0, sizeof(ctx)); + memset(&ctx, 0, sizeof(ctx)); #if defined(__COMPILED_OUT__) - if (keyLength > 64) { - // The key can be no bigger than 64 bytes. If it is, we'll hash it down to - // 20 bytes. - sha1_init(&ctx); - sha1_update(&ctx, key, keyLength); - sha1_final(&ctx, hashed_key); - key = hashed_key; - keyLength = SHA1_DIGEST_LENGTH; - } + if (keyLength > 64) { + // The key can be no bigger than 64 bytes. If it is, we'll hash it down to + // 20 bytes. + sha1_init(&ctx); + sha1_update(&ctx, key, keyLength); + sha1_final(&ctx, hashed_key); + key = hashed_key; + keyLength = SHA1_DIGEST_LENGTH; + } #endif - // The key for the inner digest is derived from our key, by padding the key - // the full length of 64 bytes, and then XOR'ing each byte with 0x36. - for (i = 0; i < keyLength; ++i) { - tmp_key[i] = key[i] ^ 0x36; - } - if (keyLength < 64) { - memset(tmp_key + keyLength, 0x36, 64 - keyLength); - } - - // Compute inner digest - sha1_init(&ctx); - sha1_update(&ctx, tmp_key, 64); - sha1_update(&ctx, data, dataLength); - sha1_final(&ctx, sha); - - // The key for the outer digest is derived from our key, by padding the key - // the full length of 64 bytes, and then XOR'ing each byte with 0x5C. - for (i = 0; i < keyLength; ++i) { - tmp_key[i] = key[i] ^ 0x5C; - } - memset(tmp_key + keyLength, 0x5C, 64 - keyLength); - - // Compute outer digest - sha1_init(&ctx); - sha1_update(&ctx, tmp_key, 64); - sha1_update(&ctx, sha, SHA1_DIGEST_LENGTH); - sha1_final(&ctx, sha); - - // Copy result to output buffer and truncate or pad as necessary - memset(result, 0, resultLength); - if (resultLength > SHA1_DIGEST_LENGTH) { - resultLength = SHA1_DIGEST_LENGTH; - } - memcpy(result, sha, resultLength); + // The key for the inner digest is derived from our key, by padding the key + // the full length of 64 bytes, and then XOR'ing each byte with 0x36. + for (i = 0; i < keyLength; ++i) { + tmp_key[i] = key[i] ^ 0x36; + } + if (keyLength < 64) { + memset(tmp_key + keyLength, 0x36, 64 - keyLength); + } + // Compute inner digest + sha1_init(&ctx); + sha1_update(&ctx, tmp_key, 64); + sha1_update(&ctx, data, dataLength); + sha1_final(&ctx, sha); + + // The key for the outer digest is derived from our key, by padding the key + // the full length of 64 bytes, and then XOR'ing each byte with 0x5C. + for (i = 0; i < keyLength; ++i) { + tmp_key[i] = key[i] ^ 0x5C; + } + memset(tmp_key + keyLength, 0x5C, 64 - keyLength); + + // Compute outer digest + sha1_init(&ctx); + sha1_update(&ctx, tmp_key, 64); + sha1_update(&ctx, sha, SHA1_DIGEST_LENGTH); + sha1_final(&ctx, sha); + + // Copy result to output buffer and truncate or pad as necessary + memset(result, 0, resultLength); + if (resultLength > SHA1_DIGEST_LENGTH) { + resultLength = SHA1_DIGEST_LENGTH; + } + memcpy(result, sha, resultLength); } diff --git a/modules/hashutils.h b/modules/hashutils.h index 1db7b0b..5095aa7 100644 --- a/modules/hashutils.h +++ b/modules/hashutils.h @@ -24,16 +24,18 @@ typedef struct { uint32_t digest[8]; uint32_t count_lo, count_hi; - uint8_t data[SHA1_BLOCKSIZE]; - int local; + uint8_t data[SHA1_BLOCKSIZE]; + int local; } SHA1_INFO; -void sha1_init(SHA1_INFO *sha1_info) __attribute__((visibility("hidden"))); -void sha1_update(SHA1_INFO *sha1_info, const uint8_t *buffer, int count) -__attribute__((visibility("hidden"))); -void sha1_final(SHA1_INFO *sha1_info, uint8_t digest[20]) -__attribute__((visibility("hidden"))); +void sha1_init(SHA1_INFO * sha1_info) + __attribute__ ((visibility("hidden"))); +void sha1_update(SHA1_INFO * sha1_info, const uint8_t * buffer, int count) + __attribute__ ((visibility("hidden"))); +void sha1_final(SHA1_INFO * sha1_info, uint8_t digest[20]) + __attribute__ ((visibility("hidden"))); -void hmac_sha1(const uint8_t *key, int keyLength, - const uint8_t *data, int dataLength, - uint8_t *result, int resultLength) __attribute__((visibility("hidden")));; +void hmac_sha1(const uint8_t * key, int keyLength, + const uint8_t * data, int dataLength, + uint8_t * result, int resultLength) + __attribute__ ((visibility("hidden")));; diff --git a/modules/hello.c b/modules/hello.c new file mode 100644 index 0000000..709ce30 --- /dev/null +++ b/modules/hello.c @@ -0,0 +1,66 @@ +/** + modules/hello.c: hello world module for openchronos-ng + + Copyright (C) 2019 Luca Lorello + + http://github.com/HashakGik/openchronos-ng-elf + + This file is part of openchronos-ng. + + openchronos-ng 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. + + openchronos-ng 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 . +**/ + +/* This module shows a scrolling hello world. + The display_scroll function will probably be included in the display driver. + */ + +#include "messagebus.h" +#include "menu.h" +#include "drivers/display.h" + +uint8_t str_counter; +char *hello = "HELLO WORLD ITS GOOD TO SEE YOU ALL"; + +void display_scroll(uint8_t scr_nr, enum display_segment_array segments, char const *str, uint8_t len, enum display_segstate state, uint8_t *i) +{ + uint8_t segnum = segments & 0x0f; + uint8_t lastchar = (segnum < len)? (len - segnum + 1): segnum; + + display_chars(scr_nr, segments, str + *i, state); + *i = (*i + 1) % lastchar; +} + + + +static void hello_interrupt(enum sys_message msg) +{ + display_scroll(0, LCD_SEG_L2_4_0, hello, 35, SEG_SET, &str_counter); +} + +static void hello_activate(void) +{ + str_counter = 0; + sys_messagebus_register(&hello_interrupt, SYS_MSG_RTC_SECOND); +} + +static void hello_deactivate(void) +{ + sys_messagebus_unregister_all(&hello_interrupt); +} + +void mod_hello_init(void) +{ + menu_add_entry("HELLO", NULL, NULL, NULL, NULL, NULL, NULL, + &hello_activate, &hello_deactivate); +} diff --git a/modules/hello.cfg b/modules/hello.cfg new file mode 100644 index 0000000..56804af --- /dev/null +++ b/modules/hello.cfg @@ -0,0 +1,5 @@ +[HELLO] +menu_order = 97 +name = Hello +default = false +help = Scrolling Hello World message. \ No newline at end of file diff --git a/modules/music.c b/modules/music.c index 084f5be..9d5347b 100644 --- a/modules/music.c +++ b/modules/music.c @@ -1,24 +1,24 @@ /** - modules/music.c: Buzzer music module for openchronos-ng + modules/music.c: Buzzer music module for openchronos-ng - Copyright (C) 2012 Angelo Arrifano + Copyright (C) 2012 Angelo Arrifano - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ #include "messagebus.h" @@ -29,34 +29,30 @@ #include "drivers/buzzer.h" /* tunes generated using contrib/rtttl2bin.py */ -/* super mario bros tune */ -static note smb[] = {0x25a8, 0x25a8, 0x12d0, 0x4b28, 0x25a4, 0x4b28, 0x4b2b, 0x4b10, 0x4b1b, 0x4b10, 0x4b24, 0x2590, 0x4b1b, 0x2590, 0x4b18, 0x2590, 0x4b11, 0x4b13, 0x2592, 0x4b11, 0x191b, 0x25a8, 0x25ab, 0x4b21, 0x25a9, 0x4b2b, 0x4b28, 0x25a4, 0x25a6, 0x4b13, 0x2590, 0x4b24, 0x2590, 0x4b1b, 0x2590, 0x4b18, 0x2590, 0x4b11, 0x4b13, 0x2592, 0x4b11, 0x191b, 0x25a8, 0x25ab, 0x4b21, 0x25a9, 0x4b2b, 0x4b28, 0x25a4, 0x25a6, 0x4b13, 0x4b10, 0x25ab, 0x25aa, 0x25a9, 0x25a7, 0x2590, 0x25a8, 0x2590, 0x259c, 0x2591, 0x25a4, 0x2590, 0x2591, 0x25a4, 0x25a6, 0x4b10, 0x25ab, 0x25aa, 0x25a9, 0x25a7, 0x2590, 0x25a8, 0x2590, 0x25b4, 0x2590, 0x25b4, 0x25b4, 0x9610, 0x25ab, 0x25aa, 0x25a9, 0x25a7, 0x2590, 0x25a8, 0x2590, 0x259c, 0x2591, 0x25a4, 0x2590, 0x2591, 0x25a4, 0x25a6, 0x4b10, 0x25a7, 0x4b10, 0x25a6, 0x4b10, 0x25a4, 0x000F}; +/* nokia tune */ +static note nokia[] = {0x25a8, 0x25a6, 0x4b1a, 0x4b1c, 0x25a5, 0x2593, 0x4b16, 0x4b18, 0x2593, 0x2591, 0x4b15, 0x4b18, 0x6411, 0x000F}; static void num_press() { - buzzer_play(smb); + buzzer_play(nokia); } static void music_activate() { - display_chars(0, LCD_SEG_L2_4_0, "MUSIC", SEG_ON); + display_chars(0, LCD_SEG_L2_4_0, "MUSIC", SEG_ON); } static void music_deactivate() { - display_clear(0, 2); + display_clear(0, 2); } void mod_music_init(void) { - menu_add_entry("MUSIC", - NULL, - NULL, - &num_press, - NULL, - NULL, - NULL, - &music_activate, - &music_deactivate); + menu_add_entry("MUSIC", + NULL, + NULL, + &num_press, + NULL, NULL, NULL, &music_activate, &music_deactivate); } diff --git a/modules/music.cfg b/modules/music.cfg index 9592ce6..675018e 100644 --- a/modules/music.cfg +++ b/modules/music.cfg @@ -1,5 +1,4 @@ [MUSIC] -menu_order = 80 +menu_order = 32 name = Music -help = Plays a music tone (Super Mario by default) - +help = Plays a music tone (Nokia tune). diff --git a/modules/otp.c b/modules/otp.c index 96b40a0..c8da11d 100644 --- a/modules/otp.c +++ b/modules/otp.c @@ -1,24 +1,24 @@ /** - Copyright (c) 2011 Yohanes Nugroho (yohanes@gmail.com) - Copyright (c) 2016-17 Benjamin Sølberg (benjamin.soelberg@gmail.com) - Copyright (c) 2016-17 menehune dune + Copyright (c) 2011 Yohanes Nugroho (yohanes@gmail.com) + Copyright (c) 2016-17 Benjamin Sølberg (benjamin.soelberg@gmail.com) + Copyright (c) 2016-17 menehune dune - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ @@ -50,37 +50,40 @@ #define SEG_F (BIT0) #define SEG_G (BIT1) -static int days[12] ={0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; +static int days[12] = +{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; #if defined(CONFIG_MOD_OTP_SOUND_CUE) int8_t otp_sound_cue = 0; int8_t otp_first_code = 1; #endif -uint32_t simple_mktime(int year, int month, int day, int hour, int minute, int second) +uint32_t simple_mktime(int year, int month, int day, int hour, int minute, + int second) { - //only works for year 2000 - 2032 - uint32_t result; + //only works for year 2000 - 2032 + uint32_t result; - year += month / 12; - month %= 12; - result = (year - 1970) * 365 + days[month]; - if (month <= 1) year--; + year += month / 12; + month %= 12; + result = (year - 1970) * 365 + days[month]; + if (month <= 1) + year--; - result += (year - 1968) / 4; - result += day - 1; - result = ((result * 24 + hour) * 60 + minute) * 60 + second; + result += (year - 1968) / 4; + result += day - 1; + result = ((result * 24 + hour) * 60 + minute) * 60 + second; #if defined(CONFIG_RTC_DST) - if (rtc_dst_state == RTC_DST_STATE_DST) { - result = result - 3600; - } + if (rtc_dst_state == RTC_DST_STATE_DST) { + result = result - 3600; + } #endif - return result; + return result; } -const keystore_t otp_keys[] = CONFIG_MOD_OTP_KEYS; +const keystore_t otp_keys[] = CONFIG_MOD_OTP_KEYS; #define NUM_ELEMS(x) (sizeof(x)/sizeof(x[0])) #define NUM_KEYS NUM_ELEMS(otp_keys) @@ -88,170 +91,173 @@ const keystore_t otp_keys[] = CONFIG_MOD_OTP_KEYS; static uint8_t current_key_index = 0; static uint8_t max_key_index = NUM_KEYS; -static uint32_t last_time = 0; -static uint8_t otp_data[] = {0,0,0,0,0,0,0,0}; -static uint8_t otp_result[SHA1_DIGEST_LENGTH]; -static uint8_t indicator[] = { - SEG_A+SEG_F+SEG_E+SEG_D+SEG_C+SEG_B, SEG_B, - SEG_A+SEG_F+SEG_E+SEG_D+SEG_C, SEG_C, - SEG_A+SEG_F+SEG_E+SEG_D, SEG_D, - SEG_A+SEG_F+SEG_E, SEG_E, - SEG_A+SEG_F, SEG_F, - SEG_A, SEG_A +static uint32_t last_time = 0; +static uint8_t otp_data[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +static uint8_t otp_result[SHA1_DIGEST_LENGTH]; +static uint8_t indicator[] = { + SEG_A + SEG_F + SEG_E + SEG_D + SEG_C + SEG_B, SEG_B, + SEG_A + SEG_F + SEG_E + SEG_D + SEG_C, SEG_C, + SEG_A + SEG_F + SEG_E + SEG_D, SEG_D, + SEG_A + SEG_F + SEG_E, SEG_E, + SEG_A + SEG_F, SEG_F, + SEG_A, SEG_A }; -static void otp_get_current_params(char *potp_identifier, - const uint8_t **potp_key, uint8_t *potp_key_len) +static void otp_get_current_params(char *potp_identifier, + const uint8_t ** potp_key, + uint8_t * potp_key_len) { - const keystore_t *current_key = &otp_keys[current_key_index]; - /*only a single char is supported right now*/ - *potp_identifier = current_key->otp_identifier[0]; - *potp_key = (const uint8_t *)current_key->otp_key; - *potp_key_len = current_key->otp_key_len; + const keystore_t *current_key = &otp_keys[current_key_index]; + /*only a single char is supported right now */ + *potp_identifier = current_key->otp_identifier[0]; + *potp_key = (const uint8_t *) current_key->otp_key; + *potp_key_len = current_key->otp_key_len; } -static uint32_t calculate_otp(uint32_t time, const uint8_t *otp_key, - uint8_t otp_key_len) +static uint32_t calculate_otp(uint32_t time, const uint8_t * otp_key, + uint8_t otp_key_len) { - uint32_t val = 0; - int i; + uint32_t val = 0; + int i; - memset(otp_data, 0, sizeof(otp_data)); - memset(otp_result, 0, sizeof(otp_result)); + memset(otp_data, 0, sizeof(otp_data)); + memset(otp_result, 0, sizeof(otp_result)); - otp_data[4] = (time >> 24) & 0xff; - otp_data[5] = (time >> 16) & 0xff; - otp_data[6] = (time >> 8 ) & 0xff; - otp_data[7] = (time ) & 0xff; - + otp_data[4] = (time >> 24) & 0xff; + otp_data[5] = (time >> 16) & 0xff; + otp_data[6] = (time >> 8) & 0xff; + otp_data[7] = (time) & 0xff; - hmac_sha1(otp_key, otp_key_len, otp_data, sizeof(otp_data), - otp_result, sizeof(otp_result)); - int off = otp_result[SHA1_DIGEST_LENGTH - 1] & 0x0f; + hmac_sha1(otp_key, otp_key_len, otp_data, sizeof(otp_data), + otp_result, sizeof(otp_result)); - char *cc = (char *)&val; - for (i =0; i < 4; i++) { - cc[3-i] = otp_result[off+i]; - } - val &= 0x7fffffff; - val %= 1000000; + int off = otp_result[SHA1_DIGEST_LENGTH - 1] & 0x0f; - return val; + char *cc = (char *) &val; + for (i = 0; i < 4; i++) { + cc[3 - i] = otp_result[off + i]; + } + val &= 0x7fffffff; + val %= 1000000; + + return val; } static void clock_event(enum sys_message msg) { - // Check how long the current code is valid - uint8_t segment = (rtca_time.sec / 5) % 6; - - char otp_identifier; - const uint8_t *otp_key; - uint8_t otp_key_len; - - otp_get_current_params(&otp_identifier, &otp_key, &otp_key_len); - // Draw indicator in lower-left corner - display_bits(0, LCD_SEG_L2_4, indicator[2*segment ], SEG_SET); - display_bits(0, LCD_SEG_L2_4, indicator[2*segment+1], BLINK_SET); - display_char(0 ,LCD_SEG_L1_3, otp_identifier, SEG_SET); - - // Calculate timestamp - uint32_t time = simple_mktime(rtca_time.year, rtca_time.mon - 1, rtca_time.day, - rtca_time.hour, rtca_time.min , rtca_time.sec); - time = (time - CONFIG_MOD_OTP_OFFSET * 3600) / 30; - - // Check if new code must be calculated - if(time != last_time) { - - last_time = time; - uint32_t otp_value = calculate_otp(time,otp_key, otp_key_len); - - // Draw first half on the top line - uint16_t v = (otp_value / 1000) % 1000; - _printf(0, LCD_SEG_L1_2_0, "%03u", v); - - // Draw second half on the bottom line - v = (otp_value % 1000); - _printf(0, LCD_SEG_L2_2_0,"%03u", v); + // Check how long the current code is valid + uint8_t segment = (rtca_time.sec / 5) % 6; + + char otp_identifier; + const uint8_t *otp_key; + uint8_t otp_key_len; + + otp_get_current_params(&otp_identifier, &otp_key, &otp_key_len); + // Draw indicator in lower-left corner + display_bits(0, LCD_SEG_L2_4, indicator[2 * segment], SEG_SET); + display_bits(0, LCD_SEG_L2_4, indicator[2 * segment + 1], BLINK_SET); + display_char(0, LCD_SEG_L1_3, otp_identifier, SEG_SET); + + // Calculate timestamp + uint32_t time = + simple_mktime(rtca_time.year, rtca_time.mon - 1, rtca_time.day, + rtca_time.hour, rtca_time.min, rtca_time.sec); + time = (time - CONFIG_MOD_OTP_OFFSET * 3600) / 30; + + // Check if new code must be calculated + if (time != last_time) { + + last_time = time; + uint32_t otp_value = calculate_otp(time, otp_key, otp_key_len); + + // Draw first half on the top line + uint16_t v = (otp_value / 1000) % 1000; + _printf(0, LCD_SEG_L1_2_0, "%03u", v); + + // Draw second half on the bottom line + v = (otp_value % 1000); + _printf(0, LCD_SEG_L2_2_0, "%03u", v); #if defined(CONFIG_MOD_OTP_SOUND_CUE) - extern note welcome[4]; - if (!otp_first_code && otp_sound_cue) - buzzer_play(welcome); - otp_first_code = 0; + extern note welcome[4]; + if (!otp_first_code && otp_sound_cue) + buzzer_play(welcome); + otp_first_code = 0; #endif - } + } } static void otp_request_update(bool activated) { - enum sys_message ev_type = activated ? SYS_MSG_RTC_SECOND : SYS_MSG_NONE; + enum sys_message ev_type = + activated ? SYS_MSG_RTC_SECOND : SYS_MSG_NONE; #if defined(CONFIG_MOD_OTP_SOUND_CUE) - otp_first_code = 1; + otp_first_code = 1; #endif - // Force generate & display a new OTP - last_time = 0; - clock_event(ev_type); + // Force generate & display a new OTP + last_time = 0; + clock_event(ev_type); } static void otp_activated() { - sys_messagebus_register(&clock_event, SYS_MSG_RTC_SECOND); - display_char(0 ,LCD_SEG_L1_3, '8', BLINK_ON); + sys_messagebus_register(&clock_event, SYS_MSG_RTC_SECOND); + display_char(0, LCD_SEG_L1_3, '8', BLINK_ON); #if defined(CONFIG_MOD_OTP_SOUND_CUE) - display_bits(0, LCD_SEG_L2_3, SEG_G, otp_sound_cue ? SEG_ON : SEG_OFF); + display_bits(0, LCD_SEG_L2_3, SEG_G, otp_sound_cue ? SEG_ON : SEG_OFF); #endif - otp_request_update(true); + otp_request_update(true); } static void otp_deactivated() { - sys_messagebus_unregister_all(&clock_event); - display_char(0 ,LCD_SEG_L1_3, '8', BLINK_OFF); - /* clean up screen */ - display_clear(0, 1); - display_clear(0, 2); + sys_messagebus_unregister_all(&clock_event); + display_char(0, LCD_SEG_L1_3, '8', BLINK_OFF); + /* clean up screen */ + display_clear(0, 1); + display_clear(0, 2); } static void otp_gen_next() { - if (current_key_index == max_key_index - 1) - current_key_index = 0; - else - current_key_index++; - otp_request_update(false); + if (current_key_index == max_key_index - 1) + current_key_index = 0; + else + current_key_index++; + otp_request_update(false); } static void otp_gen_prev() { - if (current_key_index == 0) - current_key_index = max_key_index - 1; - else - current_key_index--; - otp_request_update(false); + if (current_key_index == 0) + current_key_index = max_key_index - 1; + else + current_key_index--; + otp_request_update(false); } #if defined(CONFIG_MOD_OTP_SOUND_CUE) static void otp_toggle_beep() { - otp_sound_cue ^= 1; - display_bits(0, LCD_SEG_L2_3, SEG_G, otp_sound_cue ? SEG_ON : SEG_OFF); + otp_sound_cue ^= 1; + display_bits(0, LCD_SEG_L2_3, SEG_G, otp_sound_cue ? SEG_ON : SEG_OFF); } #endif void mod_otp_init() { - menu_add_entry("OTP", - &otp_gen_next, /* up */ - &otp_gen_prev, /* down */ + menu_add_entry("OTP", &otp_gen_next, /* up */ + &otp_gen_prev, /* down */ #if defined(CONFIG_MOD_OTP_SOUND_CUE) - &otp_toggle_beep, /* num */ + &otp_toggle_beep, /* num */ #else - NULL, /* num */ + NULL, /* num */ #endif - NULL, /* long star */ - NULL, /* long num */ - NULL, /* up-down */ - &otp_activated, /* activate */ - &otp_deactivated); /* deactivate */ + NULL, /* long star */ + NULL, /* long num */ + NULL, /* up-down */ + &otp_activated, /* activate */ + &otp_deactivated); /* deactivate */ } diff --git a/modules/otp.cfg b/modules/otp.cfg index c72c674..2ad5374 100644 --- a/modules/otp.cfg +++ b/modules/otp.cfg @@ -1,7 +1,7 @@ [OTP] -menu_order = 100 +menu_order = 33 name = Google OTP -help = Enable OTP generation +help = Enable OTP generation. depends = CONFIG_RTC_IRQ [OTP_KEYS] @@ -9,18 +9,18 @@ name = OTP Keys type = text default = encoding = b32encode -help = OTP Key in base32 encoded format (spaces will be ignored). For multiple keys use ',' +help = OTP Key in base32 encoded format (spaces will be ignored). For multiple keys use ','. [OTP_OFFSET] name = Offset from UTC (leave this empty to use system timezone setting) type = text default = encoding = tzget -help = Offset from UTC in hours (can be negative) +help = Offset from UTC in hours (can be negative). [OTP_SOUND_CUE] name = Generate OTP expiry sound, press '#' in otp mode to toggle type = bool default = -help = Generate a buzzer sound when otp has expired, Turn on by pressing '#' in otp mode +help = Generate a buzzer sound when otp has expired, Turn on by pressing '#' in otp mode. diff --git a/modules/otp.h b/modules/otp.h index 20bf8b1..0557515 100644 --- a/modules/otp.h +++ b/modules/otp.h @@ -18,10 +18,9 @@ #ifndef __OTP_H__ #define __OTP_H__ #include -typedef struct keystore -{ - const char *otp_identifier; - const char *otp_key; +typedef struct keystore { + const char *otp_identifier; + const char *otp_key; const uint8_t otp_key_len; -}keystore_t; +} keystore_t; #endif diff --git a/modules/reset.c b/modules/reset.c index 2e44c88..28155cb 100644 --- a/modules/reset.c +++ b/modules/reset.c @@ -1,25 +1,25 @@ /** - modules/reset.c: Reset module for openchronos-ng + modules/reset.c: Reset module for openchronos-ng - Copyright (C) 2012-2013 Angelo Arrifano - Copyright (C) 2016-2017 Benjamin Sølberg + Copyright (C) 2012-2013 Angelo Arrifano + Copyright (C) 2016-2017 Benjamin Sølberg - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ #include "messagebus.h" @@ -32,46 +32,42 @@ static void num_press() { - /* reset microcontroller */ - REBOOT(); + /* reset microcontroller */ + REBOOT(); } #ifdef CONFIG_MOD_RESET_EASY_RESET static void button_event(enum sys_message event) { - // If up and down is pressed (at the EXACT same time) then resets the watch! - // You might want to press them together a few times for this to work. - if (ports_button_pressed_peek(PORTS_BTN_UP | PORTS_BTN_DOWN, 0)) - { - num_press(); - } + // If up and down is pressed (at the EXACT same time) then resets the watch! + // You might want to press them together a few times for this to work. + if (ports_button_pressed_peek(PORTS_BTN_UP | PORTS_BTN_DOWN, 0)) { + num_press(); + } } #endif static void reset_activate() { - /* update screen */ - display_chars(0, LCD_SEG_L2_4_0, "RESET", SEG_ON); + /* update screen */ + display_chars(0, LCD_SEG_L2_4_0, "RESET", SEG_ON); } static void reset_deactivate() { - /* cleanup screen */ - display_clear(0, 2); + /* cleanup screen */ + display_clear(0, 2); } -void mod_reset_init(void) { +void mod_reset_init(void) +{ #ifdef CONFIG_MOD_RESET_EASY_RESET - sys_messagebus_register(&button_event, SYS_MSG_BUTTON); + sys_messagebus_register(&button_event, SYS_MSG_BUTTON); #endif - menu_add_entry("RESET", - NULL, - NULL, - &num_press, - NULL, - NULL, - NULL, - &reset_activate, - &reset_deactivate); + menu_add_entry("RESET", + NULL, + NULL, + &num_press, + NULL, NULL, NULL, &reset_activate, &reset_deactivate); } diff --git a/modules/reset.cfg b/modules/reset.cfg index 2bf2654..f911370 100644 --- a/modules/reset.cfg +++ b/modules/reset.cfg @@ -1,9 +1,9 @@ [RESET] -menu_order = 60 +menu_order = 100 name = Reset Module default = true -help = Resets your watch (YOU NEED THIS TO WIRELESSLY FLASH THE WATCH, SEE README) +help = Resets your watch (YOU NEED THIS TO WIRELESSLY FLASH THE WATCH, SEE README). [RESET_EASY_RESET] name = Easy Reset [FOR TESTING] -help = Makes it faster to reboot the watch by pressing up/down buttons at the same time +help = Makes it faster to reboot the watch by pressing up/down buttons at the same time. diff --git a/modules/soundspeed.c b/modules/soundspeed.c new file mode 100644 index 0000000..fdd9ae2 --- /dev/null +++ b/modules/soundspeed.c @@ -0,0 +1,139 @@ +/** + modules/soundspeed.c: speed of sound calculator module for openchronos-ng + + Copyright (C) 2019 Luca Lorello + + http://github.com/HashakGik/openchronos-ng-elf + + This file is part of openchronos-ng. + + openchronos-ng 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. + + openchronos-ng 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 . +**/ + +/* This module uses the BMP085 sensor (white PCB) to calculate the speed of sound in the current environment. + Given the current pressure (pa) and temperature (temp), air density is given by: + rho = pa / (temp * R) [ https://en.wikipedia.org/wiki/Density_of_air ] + and sound speed is given by: + speed = sqrt(gamma * pa / rho) [ https://en.wikipedia.org/wiki/Speed_of_sound#Speed_of_sound_in_ideal_gases_and_air ] + + The # key changes the displayed unit between m/s (default), km/h, mph and ft/s. + */ + +#include "messagebus.h" +#include "menu.h" +#include "config.h" + +#include "drivers/display.h" +#include "drivers/bmp_ps.h" +#include "drivers/ps.h" + +#include + +#define MS_TO_KMH(x) (x * 3.6) +#define MS_TO_MPH(x) (x * 2.237) +#define MS_TO_FTS(x) (x * 3.281) + +static uint8_t i; +static uint8_t unit; + +static void print_sound(void) +{ + float rho; + float s; + uint32_t pa = bmp_ps_get_pa(); + + rho = pa / (bmp_ps_get_temp() / 10.0 * 287.058); + s = sqrtf(1.4 * pa / rho); + + switch (unit) { + case 0: // m/s + display_symbol(0, LCD_UNIT_L1_M, SEG_SET); + display_symbol(0, LCD_UNIT_L1_PER_S, SEG_SET); + display_symbol(0, LCD_UNIT_L1_K, SEG_OFF); + display_symbol(0, LCD_UNIT_L1_PER_H, SEG_OFF); + display_symbol(0, LCD_UNIT_L1_I, SEG_OFF); + display_symbol(0, LCD_UNIT_L1_FT, SEG_OFF); + break; + case 1: // km/h + display_symbol(0, LCD_UNIT_L1_M, SEG_SET); + display_symbol(0, LCD_UNIT_L1_PER_S, SEG_OFF); + display_symbol(0, LCD_UNIT_L1_K, SEG_SET); + display_symbol(0, LCD_UNIT_L1_PER_H, SEG_SET); + display_symbol(0, LCD_UNIT_L1_I, SEG_OFF); + display_symbol(0, LCD_UNIT_L1_FT, SEG_OFF); + s = MS_TO_KMH(s); + break; + case 2: // mph + display_symbol(0, LCD_UNIT_L1_M, SEG_SET); + display_symbol(0, LCD_UNIT_L1_PER_S, SEG_OFF); + display_symbol(0, LCD_UNIT_L1_K, SEG_OFF); + display_symbol(0, LCD_UNIT_L1_PER_H, SEG_SET); + display_symbol(0, LCD_UNIT_L1_I, SEG_SET); + display_symbol(0, LCD_UNIT_L1_FT, SEG_OFF); + s = MS_TO_MPH(s); + break; + case 3: // ft/s + display_symbol(0, LCD_UNIT_L1_M, SEG_OFF); + display_symbol(0, LCD_UNIT_L1_PER_S, SEG_SET); + display_symbol(0, LCD_UNIT_L1_K, SEG_OFF); + display_symbol(0, LCD_UNIT_L1_PER_H, SEG_OFF); + display_symbol(0, LCD_UNIT_L1_I, SEG_OFF); + display_symbol(0, LCD_UNIT_L1_FT, SEG_SET); + s = MS_TO_FTS(s); + break; + } + + _printf(0, LCD_SEG_L1_3_0, "%4u", s); +} + + +static void sound_interrupt(enum sys_message msg) +{ + if (i == 0) + print_sound(); + + i = (i + 1) % CONFIG_MOD_SOUNDSPEED_REFRESH; +} + +static void num_pressed(void) +{ + unit = (unit + 1) % 4; + print_sound(); +} + +static void sound_activate(void) +{ + i = unit = 0; + bmp_ps_init(); + init_pressure_table(); + bmp_ps_start(); + + sys_messagebus_register(&sound_interrupt, SYS_MSG_RTC_SECOND); + +} + +static void sound_deactivate(void) +{ + bmp_ps_stop(); + sys_messagebus_unregister_all(&sound_interrupt); + + display_clear(0, 0); +} + + +void mod_soundspeed_init(void) +{ + menu_add_entry("SSOUN", NULL, NULL, &num_pressed, NULL, NULL, NULL, + &sound_activate, &sound_deactivate); +} diff --git a/modules/soundspeed.cfg b/modules/soundspeed.cfg new file mode 100644 index 0000000..ccf710d --- /dev/null +++ b/modules/soundspeed.cfg @@ -0,0 +1,13 @@ +[SOUNDSPEED] +menu_order = 25 +name = Speed of sound calculator +default = false +help = Calculates the speed of sound on air at current temperature and pressure. +depends = WHITE_PCB + +[SOUNDSPEED_REFRESH] +name = Speed of sound module refresh rate +ifndef = true +type = text +default = 60 +help = Pressure and temperature update (in seconds) for speed of sound calculation. \ No newline at end of file diff --git a/modules/steps.c b/modules/steps.c new file mode 100644 index 0000000..2d7365a --- /dev/null +++ b/modules/steps.c @@ -0,0 +1,82 @@ +/** + modules/steps.c: pedometer module for openchronos-ng + + Copyright (C) 2019 Luca Lorello + + http://github.com/HashakGik/openchronos-ng-elf + + This file is part of openchronos-ng. + + openchronos-ng 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. + + openchronos-ng 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 . +**/ + +#include "messagebus.h" +#include "menu.h" + +#include "drivers/display.h" +#include "drivers/as.h" +#include "drivers/bmp_as.h" +#include "drivers/timer.h" + +/* This module uses the accelerator's internal slope interrupt. This is less precise than software processing, but allows for minimal CPU and memory usage. + A slope of at least 250mg (default setting for the 8G scale) between two consecutive samples will trigger the step count. + A long # press resets the counter. +*/ + +static uint32_t steps; + +static void update_steps(enum sys_message msg) +{ + bmp_as_process_interrupt(); + steps = (steps + 1) % 200000; // Limit the step count to the maximum displayable on the display. + _printf(0, LCD_SEG_L2_5_0, "%6u", steps); +} + +static void steps_activate(void) +{ + steps = 0; + as_init(); + bmp_as_start(BMP_GRANGE_8G, BMP_BWD_31HZ, BMP_SLEEP_10MS, 1); // Filter data at 31.25Hz and set the range to 8g. + timer0_delay(1000, LPM3_bits); + + bmp_as_interrupts_t ints = bmp_as_init_interrupts(); + ints.slope_interrupt.x = 1; + ints.slope_interrupt.y = 1; + ints.slope_interrupt.z = 1; + bmp_as_enable_interrupts(ints); // Enable slope interrupt on all three axes. + + sys_messagebus_register(&update_steps, SYS_MSG_AS_INT); + display_chars(0, LCD_SEG_L2_5_0, " 0", SEG_SET); +} + +static void steps_deactivate(void) +{ + display_clear(0, 0); + sys_messagebus_unregister_all(&update_steps); + + bmp_as_disable_interrupts(); + bmp_as_stop(); +} + +static void long_num_pressed(void) +{ + steps = 0; + display_chars(0, LCD_SEG_L2_5_0, " 0", SEG_SET); +} + +void mod_steps_init(void) +{ + menu_add_entry("STEPS", NULL, NULL, NULL, NULL, &long_num_pressed, + NULL, &steps_activate, &steps_deactivate); +} diff --git a/modules/steps.cfg b/modules/steps.cfg new file mode 100644 index 0000000..59b221d --- /dev/null +++ b/modules/steps.cfg @@ -0,0 +1,5 @@ +[STEPS] +menu_order = 22 +name = Step counter +help = Counts steps walked. +depends = WHITE_PCB \ No newline at end of file diff --git a/modules/stopwatch.c b/modules/stopwatch.c index fcefaba..b87e283 100644 --- a/modules/stopwatch.c +++ b/modules/stopwatch.c @@ -86,12 +86,13 @@ struct swatch_conf sSwatch_conf; static uint8_t icon_stopwatch_on_cents; static uint8_t icon_stopwatch_off_cents; -static struct menu *menu_entry; // Kind of a hack in order to change the button allocation at runtime +static struct menu *menu_entry; // Kind of a hack in order to change the button allocation at runtime /* * Helper Functions */ -static void clear_stopwatch(void) { +static void clear_stopwatch(void) +{ sSwatch_time[SW_COUNTING].cents = 0; sSwatch_time[SW_COUNTING].hours = 0; sSwatch_time[SW_COUNTING].minutes = 0; @@ -100,163 +101,180 @@ static void clear_stopwatch(void) { sSwatch_conf.lap_act = SW_COUNTING; } -static void increment_lap_stopwatch(void) { - sSwatch_time[sSwatch_conf.laps] = sSwatch_time[SW_COUNTING]; - if (sSwatch_conf.laps < (MAX_LAPS - 1)) { - sSwatch_conf.laps++; - } +static void increment_lap_stopwatch(void) +{ + sSwatch_time[sSwatch_conf.laps] = sSwatch_time[SW_COUNTING]; + if (sSwatch_conf.laps < (MAX_LAPS - 1)) { + sSwatch_conf.laps++; + } } /* Function to write the screen */ -static void drawStopWatchScreen(void) { - if (sSwatch_conf.state != SWATCH_MODE_BACKGROUND) { - sSwatch_time[SW_DISPLAYNG] = sSwatch_time[sSwatch_conf.lap_act]; - if (SW_COUNTING == sSwatch_conf.lap_act) { - if (sSwatch_conf.state == SWATCH_MODE_OFF) { - display_chars(0, LCD_SEG_L1_3_0, "STOP", SEG_SET); - } else { - display_chars(0, LCD_SEG_L1_3_2, "LP", SEG_SET); - _printf(0, LCD_SEG_L1_1_0, "%2u", sSwatch_conf.laps); - } +static void drawStopWatchScreen(void) +{ + if (sSwatch_conf.state != SWATCH_MODE_BACKGROUND) { + sSwatch_time[SW_DISPLAYNG] = sSwatch_time[sSwatch_conf.lap_act]; + if (SW_COUNTING == sSwatch_conf.lap_act) { + if (sSwatch_conf.state == SWATCH_MODE_OFF) { + display_chars(0, LCD_SEG_L1_3_0, "STOP", SEG_SET); + } else { + display_chars(0, LCD_SEG_L1_3_2, "LP", SEG_SET); + _printf(0, LCD_SEG_L1_1_0, "%2u", sSwatch_conf.laps); + } - } else { - display_chars(0, LCD_SEG_L1_3_2, "LP", SEG_SET); - _printf(0, LCD_SEG_L1_1_0, "%2u", sSwatch_conf.lap_act +1); - } - if (sSwatch_time[SW_DISPLAYNG].minutes < 20 - && sSwatch_time[SW_DISPLAYNG].hours == 0) { - _printf(0, LCD_SEG_L2_5_4, "%02u", sSwatch_time[SW_DISPLAYNG].minutes); - _printf(0, LCD_SEG_L2_3_2, "%02u", sSwatch_time[SW_DISPLAYNG].seconds); - _printf(0, LCD_SEG_L2_1_0, "%02u", sSwatch_time[SW_DISPLAYNG].cents); - } else { - _printf(0, LCD_SEG_L2_5_4, "%02u", sSwatch_time[SW_DISPLAYNG].hours); - _printf(0, LCD_SEG_L2_3_2, "%02u", sSwatch_time[SW_DISPLAYNG].minutes); - _printf(0, LCD_SEG_L2_1_0, "%02u", sSwatch_time[SW_DISPLAYNG].seconds); - } - } - if (sSwatch_conf.state != SWATCH_MODE_OFF) { - if (sSwatch_time[SW_COUNTING].cents == icon_stopwatch_on_cents) { - display_symbol(0, LCD_ICON_STOPWATCH, SEG_ON); - } else if (sSwatch_time[SW_COUNTING].cents == icon_stopwatch_off_cents) { - display_symbol(0, LCD_ICON_STOPWATCH, SEG_OFF); - } - } else { - display_symbol(0, LCD_ICON_STOPWATCH, SEG_OFF); - } + } else { + display_chars(0, LCD_SEG_L1_3_2, "LP", SEG_SET); + _printf(0, LCD_SEG_L1_1_0, "%2u", sSwatch_conf.lap_act + 1); + } + if (sSwatch_time[SW_DISPLAYNG].minutes < 20 + && sSwatch_time[SW_DISPLAYNG].hours == 0) { + _printf(0, LCD_SEG_L2_5_4, "%02u", + sSwatch_time[SW_DISPLAYNG].minutes); + _printf(0, LCD_SEG_L2_3_2, "%02u", + sSwatch_time[SW_DISPLAYNG].seconds); + _printf(0, LCD_SEG_L2_1_0, "%02u", + sSwatch_time[SW_DISPLAYNG].cents); + } else { + _printf(0, LCD_SEG_L2_5_4, "%02u", + sSwatch_time[SW_DISPLAYNG].hours); + _printf(0, LCD_SEG_L2_3_2, "%02u", + sSwatch_time[SW_DISPLAYNG].minutes); + _printf(0, LCD_SEG_L2_1_0, "%02u", + sSwatch_time[SW_DISPLAYNG].seconds); + } + } + if (sSwatch_conf.state != SWATCH_MODE_OFF) { + if (sSwatch_time[SW_COUNTING].cents == icon_stopwatch_on_cents) { + display_symbol(0, LCD_ICON_STOPWATCH, SEG_ON); + } else if (sSwatch_time[SW_COUNTING].cents == + icon_stopwatch_off_cents) { + display_symbol(0, LCD_ICON_STOPWATCH, SEG_OFF); + } + } else { + display_symbol(0, LCD_ICON_STOPWATCH, SEG_OFF); + } } /* Function called every 5ms to increment the counters */ -static void stopwatch_event(enum sys_message msg) { - if (sSwatch_conf.state != SWATCH_MODE_OFF) { - sSwatch_time[SW_COUNTING].cents += 5; - if (sSwatch_time[SW_COUNTING].cents >= 100) { - sSwatch_time[SW_COUNTING].cents = 0; - sSwatch_time[SW_COUNTING].seconds++; - if (sSwatch_time[SW_COUNTING].seconds >= 60) { - sSwatch_time[SW_COUNTING].seconds = 0; - sSwatch_time[SW_COUNTING].minutes++; - if (sSwatch_time[SW_COUNTING].minutes >= 60) { - sSwatch_time[SW_COUNTING].minutes = 0; - sSwatch_time[SW_COUNTING].hours++; - if (sSwatch_time[SW_COUNTING].hours >= 20) { - sSwatch_time[SW_COUNTING].hours = 0; - } - } - } - } - drawStopWatchScreen(); - } +static void stopwatch_event(enum sys_message msg) +{ + if (sSwatch_conf.state != SWATCH_MODE_OFF) { + sSwatch_time[SW_COUNTING].cents += 5; + if (sSwatch_time[SW_COUNTING].cents >= 100) { + sSwatch_time[SW_COUNTING].cents = 0; + sSwatch_time[SW_COUNTING].seconds++; + if (sSwatch_time[SW_COUNTING].seconds >= 60) { + sSwatch_time[SW_COUNTING].seconds = 0; + sSwatch_time[SW_COUNTING].minutes++; + if (sSwatch_time[SW_COUNTING].minutes >= 60) { + sSwatch_time[SW_COUNTING].minutes = 0; + sSwatch_time[SW_COUNTING].hours++; + if (sSwatch_time[SW_COUNTING].hours >= 20) { + sSwatch_time[SW_COUNTING].hours = 0; + } + } + } + } + drawStopWatchScreen(); + } } /* Activation of the module */ -static void stopwatch_activated() { - display_symbol(0, LCD_SEG_L2_COL0, SEG_ON); - display_symbol(0, LCD_SEG_L2_COL1, SEG_ON); - if (sSwatch_conf.state == SWATCH_MODE_BACKGROUND) { - sSwatch_conf.state = SWATCH_MODE_ON; - } - drawStopWatchScreen(); +static void stopwatch_activated() +{ + display_symbol(0, LCD_SEG_L2_COL0, SEG_ON); + display_symbol(0, LCD_SEG_L2_COL1, SEG_ON); + if (sSwatch_conf.state == SWATCH_MODE_BACKGROUND) { + sSwatch_conf.state = SWATCH_MODE_ON; + } + drawStopWatchScreen(); } /* Deactivation of the module */ -static void stopwatch_deactivated() { - /* clean up screen */ - display_clear(0, 1); - display_clear(0, 2); - if (sSwatch_conf.state == SWATCH_MODE_ON) { - sSwatch_conf.state = SWATCH_MODE_BACKGROUND; - } else { - display_symbol(0, LCD_ICON_STOPWATCH, SEG_OFF); - display_symbol(0, LCD_SEG_L2_COL0, SEG_OFF); - display_symbol(0, LCD_SEG_L2_COL1, SEG_OFF); - } +static void stopwatch_deactivated() +{ + /* clean up screen */ + display_clear(0, 1); + display_clear(0, 2); + if (sSwatch_conf.state == SWATCH_MODE_ON) { + sSwatch_conf.state = SWATCH_MODE_BACKGROUND; + } else { + display_symbol(0, LCD_ICON_STOPWATCH, SEG_OFF); + display_symbol(0, LCD_SEG_L2_COL0, SEG_OFF); + display_symbol(0, LCD_SEG_L2_COL1, SEG_OFF); + } } -static void down_press() { - if (sSwatch_conf.state == SWATCH_MODE_ON) { - increment_lap_stopwatch(); - } else if (sSwatch_conf.laps != 0) { - if (sSwatch_conf.lap_act == 0) { - sSwatch_conf.lap_act = SW_COUNTING; - } else if (sSwatch_conf.lap_act == SW_COUNTING) { - sSwatch_conf.lap_act = sSwatch_conf.laps - 1; - } else { - sSwatch_conf.lap_act--; - } - drawStopWatchScreen(); - } +static void down_press() +{ + if (sSwatch_conf.state == SWATCH_MODE_ON) { + increment_lap_stopwatch(); + } else if (sSwatch_conf.laps != 0) { + if (sSwatch_conf.lap_act == 0) { + sSwatch_conf.lap_act = SW_COUNTING; + } else if (sSwatch_conf.lap_act == SW_COUNTING) { + sSwatch_conf.lap_act = sSwatch_conf.laps - 1; + } else { + sSwatch_conf.lap_act--; + } + drawStopWatchScreen(); + } } -static void up_press() { - if (sSwatch_conf.state == SWATCH_MODE_ON) { - increment_lap_stopwatch(); - } else if (sSwatch_conf.laps != 0) { - if (sSwatch_conf.lap_act == sSwatch_conf.laps - 1) { - sSwatch_conf.lap_act = SW_COUNTING; - } else if (sSwatch_conf.lap_act == SW_COUNTING) { - sSwatch_conf.lap_act = 0; - } else { - sSwatch_conf.lap_act++; - } - drawStopWatchScreen(); - } +static void up_press() +{ + if (sSwatch_conf.state == SWATCH_MODE_ON) { + increment_lap_stopwatch(); + } else if (sSwatch_conf.laps != 0) { + if (sSwatch_conf.lap_act == sSwatch_conf.laps - 1) { + sSwatch_conf.lap_act = SW_COUNTING; + } else if (sSwatch_conf.lap_act == SW_COUNTING) { + sSwatch_conf.lap_act = 0; + } else { + sSwatch_conf.lap_act++; + } + drawStopWatchScreen(); + } } -static void num_long_pressed() { - clear_stopwatch(); - menu_entry->lnum_btn_fn = NULL; - drawStopWatchScreen(); +static void num_long_pressed() +{ + clear_stopwatch(); + menu_entry->lnum_btn_fn = NULL; + drawStopWatchScreen(); } -static void num_press() { - if (sSwatch_conf.state == SWATCH_MODE_OFF) { - sSwatch_conf.state = SWATCH_MODE_ON; - sSwatch_conf.lap_act = SW_COUNTING; - menu_entry->lnum_btn_fn = NULL; - icon_stopwatch_on_cents = sSwatch_time[SW_COUNTING].cents; - icon_stopwatch_off_cents = (icon_stopwatch_on_cents + 50) % 100; - sys_messagebus_register(&stopwatch_event, SYS_MSG_TIMER_20HZ); - start_timer0_20hz(); - } else { - sSwatch_conf.state = SWATCH_MODE_OFF; - menu_entry->lnum_btn_fn = &num_long_pressed; - stop_timer0_20hz(); - sys_messagebus_unregister_all(&stopwatch_event); - } - drawStopWatchScreen(); +static void num_press() +{ + if (sSwatch_conf.state == SWATCH_MODE_OFF) { + sSwatch_conf.state = SWATCH_MODE_ON; + sSwatch_conf.lap_act = SW_COUNTING; + menu_entry->lnum_btn_fn = NULL; + icon_stopwatch_on_cents = sSwatch_time[SW_COUNTING].cents; + icon_stopwatch_off_cents = (icon_stopwatch_on_cents + 50) % 100; + sys_messagebus_register(&stopwatch_event, SYS_MSG_TIMER_20HZ); + start_timer0_20hz(); + } else { + sSwatch_conf.state = SWATCH_MODE_OFF; + menu_entry->lnum_btn_fn = &num_long_pressed; + stop_timer0_20hz(); + sys_messagebus_unregister_all(&stopwatch_event); + } + drawStopWatchScreen(); } -void mod_stopwatch_init(void) { - sSwatch_conf.state = SWATCH_MODE_OFF; - clear_stopwatch(); +void mod_stopwatch_init(void) +{ + sSwatch_conf.state = SWATCH_MODE_OFF; + clear_stopwatch(); - menu_entry = menu_add_entry("STOP", - &up_press, - &down_press, - &num_press, - NULL, - NULL, - NULL, - &stopwatch_activated, - &stopwatch_deactivated); + menu_entry = menu_add_entry("STOP", + &up_press, + &down_press, + &num_press, + NULL, + NULL, + NULL, + &stopwatch_activated, + &stopwatch_deactivated); } diff --git a/modules/stopwatch.cfg b/modules/stopwatch.cfg index 702a8e0..2a4a6e5 100644 --- a/modules/stopwatch.cfg +++ b/modules/stopwatch.cfg @@ -1,5 +1,5 @@ [STOPWATCH] -menu_order = 20 +menu_order = 2 name = StopWatch default = true -help = Simply a stop watch +help = Simply a stop watch. \ No newline at end of file diff --git a/modules/temperature.c b/modules/temperature.c index 8fe19a8..5e17c04 100644 --- a/modules/temperature.c +++ b/modules/temperature.c @@ -1,26 +1,26 @@ /** - temperature.c: temperature display module + temperature.c: temperature display module - Copyright (C) 2012 Angelo Arrifano - Copyright (C) 2012 Matthew Excell - Copyright (C) 2016 Benjamin Sølberg + Copyright (C) 2012 Angelo Arrifano + Copyright (C) 2012 Matthew Excell + Copyright (C) 2016 Benjamin Sølberg - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ #include "messagebus.h" @@ -42,128 +42,131 @@ static uint8_t sec; static void display_temperature(void) { - int16_t temp; - if (use_temperature_metric) - temperature_get_C(&temp); - else - temperature_get_F(&temp); - - _printf(0, LCD_SEG_L1_3_1, "%2s", temp/10); - display_char(0, LCD_SEG_L1_0, (temp%10)+48, SEG_SET); + int16_t temp; + if (use_temperature_metric) + temperature_get_C(&temp); + else + temperature_get_F(&temp); + + _printf(0, LCD_SEG_L1_3_1, "%2s", temp / 10); + display_char(0, LCD_SEG_L1_0, (temp % 10) + 48, SEG_SET); } static void event_1_sec_callback(enum sys_message msg) { - if (++sec >= TEMP_UPDATE_INTERVAL_IN_SEC) { - temperature_measurement(); - display_temperature(); - sec = 0; - } + if (++sec >= TEMP_UPDATE_INTERVAL_IN_SEC) { + temperature_measurement(); + display_temperature(); + sec = 0; + } } /********************* edit mode callbacks ********************************/ static void display_temp_text_on_line_2() { - display_chars(0, LCD_SEG_L2_4_1, "TEMP", SEG_SET); + display_chars(0, LCD_SEG_L2_4_1, "TEMP", SEG_SET); } // Offset void update_offset_display() { - _printf(0, LCD_SEG_L2_5_0, " C%03s", temperature.offset); // C for Calibration + _printf(0, LCD_SEG_L2_5_0, " C%03s", temperature.offset); // C for Calibration } + static void edit_offset_sel(void) { - display_clear(0, 2); - display_chars(0, LCD_SEG_L2_3_0, NULL, BLINK_ON); - update_offset_display(); + display_clear(0, 2); + display_chars(0, LCD_SEG_L2_3_0, NULL, BLINK_ON); + update_offset_display(); } + static void edit_offset_dsel(void) { - display_clear(0, 2); - display_chars(0, LCD_SEG_L2_3_0, NULL, BLINK_OFF); + display_clear(0, 2); + display_chars(0, LCD_SEG_L2_3_0, NULL, BLINK_OFF); } + static void edit_offset_set(int8_t step) { - temperature.offset += step; - update_offset_display(); - display_temperature(); + temperature.offset += step; + update_offset_display(); + display_temperature(); } // C or F static void update_c_or_f_display() { - if (use_temperature_metric) { - display_chars(0, LCD_SEG_L2_5_0, " USE\\C", SEG_SET); - } else { - display_chars(0, LCD_SEG_L2_5_0, " USE\\F", SEG_SET); - } + if (use_temperature_metric) { + display_chars(0, LCD_SEG_L2_5_0, " USE\\C", SEG_SET); + } else { + display_chars(0, LCD_SEG_L2_5_0, " USE\\F", SEG_SET); + } } + static void edit_c_or_f_sel(void) { - display_clear(0, 2); - display_chars(0, LCD_SEG_L2_1_0, NULL, BLINK_ON); - update_c_or_f_display(); + display_clear(0, 2); + display_chars(0, LCD_SEG_L2_1_0, NULL, BLINK_ON); + update_c_or_f_display(); } + static void edit_c_or_f_dsel(void) { - display_clear(0, 2); - display_chars(0, LCD_SEG_L2_1_0, NULL, BLINK_OFF); + display_clear(0, 2); + display_chars(0, LCD_SEG_L2_1_0, NULL, BLINK_OFF); } static void edit_c_or_f_set(int8_t step) { - use_temperature_metric ^= 1; - update_c_or_f_display(); - display_temperature(); + use_temperature_metric ^= 1; + update_c_or_f_display(); + display_temperature(); } /************************** menu callbacks ********************************/ static struct menu_editmode_item edit_items[] = { - {&edit_offset_sel, &edit_offset_dsel, &edit_offset_set}, - {&edit_c_or_f_sel, &edit_c_or_f_dsel, &edit_c_or_f_set}, - { NULL }, + {&edit_offset_sel, &edit_offset_dsel, &edit_offset_set}, + {&edit_c_or_f_sel, &edit_c_or_f_dsel, &edit_c_or_f_set}, + {NULL}, }; static void temperature_activate(void) { - sec = TEMP_UPDATE_INTERVAL_IN_SEC; // Force update of temp delayed max 1 sec. - /* display static elements */ - display_symbol(0, LCD_UNIT_L1_DEGREE, SEG_ON); - display_symbol(0, LCD_SEG_L1_DP0, SEG_ON); - - /* display -- symbol while a measure is not performed */ - display_chars(0, LCD_SEG_L1_2_0, "---", SEG_ON); - display_temp_text_on_line_2(); - sys_messagebus_register(&event_1_sec_callback, SYS_MSG_RTC_SECOND); + sec = TEMP_UPDATE_INTERVAL_IN_SEC; // Force update of temp delayed max 1 sec. + /* display static elements */ + display_symbol(0, LCD_UNIT_L1_DEGREE, SEG_ON); + display_symbol(0, LCD_SEG_L1_DP0, SEG_ON); + + /* display -- symbol while a measure is not performed */ + display_chars(0, LCD_SEG_L1_2_0, "---", SEG_ON); + display_temp_text_on_line_2(); + sys_messagebus_register(&event_1_sec_callback, SYS_MSG_RTC_SECOND); } static void temperature_deactivate(void) { - sys_messagebus_unregister_all(&event_1_sec_callback); + sys_messagebus_unregister_all(&event_1_sec_callback); - /* cleanup screen */ - display_symbol(0, LCD_UNIT_L1_DEGREE, SEG_OFF); - display_symbol(0, LCD_SEG_L1_DP0, SEG_OFF); + /* cleanup screen */ + display_symbol(0, LCD_UNIT_L1_DEGREE, SEG_OFF); + display_symbol(0, LCD_SEG_L1_DP0, SEG_OFF); } static void temperature_edit(void) { - /* We go into edit mode */ - menu_editmode_start(&display_temp_text_on_line_2, NULL, edit_items); + /* We go into edit mode */ + menu_editmode_start(&display_temp_text_on_line_2, NULL, edit_items); } void mod_temperature_init(void) { - menu_add_entry("TEMP", - NULL, - NULL, - NULL, - &temperature_edit, - NULL, - NULL, - &temperature_activate, - &temperature_deactivate); + menu_add_entry("TEMP", + NULL, + NULL, + NULL, + &temperature_edit, + NULL, + NULL, &temperature_activate, &temperature_deactivate); } diff --git a/modules/temperature.cfg b/modules/temperature.cfg index 68df3f1..a961030 100644 --- a/modules/temperature.cfg +++ b/modules/temperature.cfg @@ -1,5 +1,5 @@ [TEMPERATURE] -menu_order = 40 +menu_order = 30 name = Temperature Display default = true -help = Displays Temperature +help = Displays Temperature. \ No newline at end of file diff --git a/modules/tide.c b/modules/tide.c index 7c7cea9..df5c2ca 100644 --- a/modules/tide.c +++ b/modules/tide.c @@ -1,24 +1,24 @@ /** - modules/tide.c: tide module for openchronos-ng + modules/tide.c: tide module for openchronos-ng - Copyright (C) 2012 Thomas Post + Copyright (C) 2012 Thomas Post - http://github.com/BenjaminSoelberg/openchronos-ng-elf + http://github.com/BenjaminSoelberg/openchronos-ng-elf - This file is part of openchronos-ng. + This file is part of openchronos-ng. - openchronos-ng 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. + openchronos-ng 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. - openchronos-ng 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. + openchronos-ng 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . **/ #include "messagebus.h" @@ -29,24 +29,24 @@ #include "drivers/display.h" struct Tide { - uint8_t hoursLeft; /* hours left to next low tide */ - uint8_t minutesLeft; /* minutes left to next low tide */ + uint8_t hoursLeft; /* hours left to next low tide */ + uint8_t minutesLeft; /* minutes left to next low tide */ }; enum tide_display_state { - TIDE_DISPLAY_STATE_GRAPH = 0, - TIDE_DISPLAY_STATE_TOLOWCOUNTER, - TIDE_DISPLAY_STATE_TOHIGHCOUNTER, - /* editing mode */ - TIDE_DISPLAY_STATE_EDITING, + TIDE_DISPLAY_STATE_GRAPH = 0, + TIDE_DISPLAY_STATE_TOLOWCOUNTER, + TIDE_DISPLAY_STATE_TOHIGHCOUNTER, + /* editing mode */ + TIDE_DISPLAY_STATE_EDITING, }; /* time to the next low tide */ static struct Tide tide; -static const uint16_t twentyFourHoursInMinutes = (uint32_t)1440; -static const uint16_t fullTideTime = (uint16_t)754; -static const uint16_t halfTideTime = (uint16_t)372; /* .5; */ +static const uint16_t twentyFourHoursInMinutes = (uint32_t) 1440; +static const uint16_t fullTideTime = (uint16_t) 754; +static const uint16_t halfTideTime = (uint16_t) 372; /* .5; */ /* state of the display */ static uint8_t moduleActivated; @@ -54,11 +54,12 @@ static uint8_t editModeActivated; static enum tide_display_state activeDisplay = TIDE_DISPLAY_STATE_GRAPH; static const char *graphs[4] = { - "_[^]_", - "[^]_[", - "^]_[^", - "]_[^]" + "_[^]_", + "[^]_[", + "^]_[^", + "]_[^]" }; + static uint8_t graphOffset; /* editing state */ @@ -67,281 +68,279 @@ static struct Tide enteredTimeOfNextLow; /* MARK: Helper Functions */ uint16_t timeInMinutes(struct Tide aTide) { - uint16_t result = (uint16_t)aTide.minutesLeft; - result += (uint16_t)aTide.hoursLeft * (uint16_t)60; - return result; + uint16_t result = (uint16_t) aTide.minutesLeft; + result += (uint16_t) aTide.hoursLeft * (uint16_t) 60; + return result; } uint16_t timeNowInMinutes(void) { - struct Tide timeNow; + struct Tide timeNow; - timeNow.hoursLeft = rtca_time.hour; - timeNow.minutesLeft = rtca_time.min; - if (rtca_time.sec > 30) - timeNow.minutesLeft++; - return timeInMinutes(timeNow); + timeNow.hoursLeft = rtca_time.hour; + timeNow.minutesLeft = rtca_time.min; + if (rtca_time.sec > 30) + timeNow.minutesLeft++; + return timeInMinutes(timeNow); } struct Tide timeFromMinutes(uint16_t minutes) { - struct Tide newTide; + struct Tide newTide; - newTide.hoursLeft = minutes/60; + newTide.hoursLeft = minutes / 60; - uint16_t hoursInMinutes = (uint16_t)newTide.hoursLeft*(uint32_t)60; - minutes -= hoursInMinutes; - newTide.minutesLeft = minutes; + uint16_t hoursInMinutes = (uint16_t) newTide.hoursLeft * (uint32_t) 60; + minutes -= hoursInMinutes; + newTide.minutesLeft = minutes; - return newTide; + return newTide; } /* MARK: Drawing */ void blinkCol(uint8_t screen, uint8_t line) { - switch (line) { - case 1: - display_symbol(screen, LCD_SEG_L1_COL, SEG_ON); - display_symbol(screen, LCD_SEG_L1_COL, BLINK_ON); - break; - case 2: - display_symbol(screen, LCD_SEG_L2_COL0, SEG_ON); - display_symbol(screen, LCD_SEG_L2_COL0, BLINK_ON); - break; - default: - break; - } + switch (line) { + case 1: + display_symbol(screen, LCD_SEG_L1_COL, SEG_ON); + display_symbol(screen, LCD_SEG_L1_COL, BLINK_ON); + break; + case 2: + display_symbol(screen, LCD_SEG_L2_COL0, SEG_ON); + display_symbol(screen, LCD_SEG_L2_COL0, BLINK_ON); + break; + default: + break; + } } void drawScreen(void) { - /* do nothing if not visible */ - if (!moduleActivated || editModeActivated) - return; + /* do nothing if not visible */ + if (!moduleActivated || editModeActivated) + return; - display_clear(0, 0); - display_clear(1, 0); - display_clear(2, 0); + display_clear(0, 0); + display_clear(1, 0); + display_clear(2, 0); - uint16_t nowInMinutes = timeNowInMinutes(); - uint16_t leftUntilLow = timeInMinutes(tide); - uint16_t leftUntilHigh = halfTideTime; + uint16_t nowInMinutes = timeNowInMinutes(); + uint16_t leftUntilLow = timeInMinutes(tide); + uint16_t leftUntilHigh = halfTideTime; - if (leftUntilLow > leftUntilHigh) - leftUntilHigh = leftUntilLow - leftUntilHigh; - else - leftUntilHigh = leftUntilLow + leftUntilHigh; + if (leftUntilLow > leftUntilHigh) + leftUntilHigh = leftUntilLow - leftUntilHigh; + else + leftUntilHigh = leftUntilLow + leftUntilHigh; - struct Tide lowTide = tide; - struct Tide highTide = timeFromMinutes(leftUntilHigh); + struct Tide lowTide = tide; + struct Tide highTide = timeFromMinutes(leftUntilHigh); - /* screen 0 //graph + time till next peak */ - /* line1 time */ - if (leftUntilHigh < leftUntilLow) { - /* show time till high */ - _printf(0, LCD_SEG_L1_3_2, "%02u", highTide.hoursLeft); - _printf(0, LCD_SEG_L1_1_0, "%02u", highTide.minutesLeft); + /* screen 0 //graph + time till next peak */ + /* line1 time */ + if (leftUntilHigh < leftUntilLow) { + /* show time till high */ + _printf(0, LCD_SEG_L1_3_2, "%02u", highTide.hoursLeft); + _printf(0, LCD_SEG_L1_1_0, "%02u", highTide.minutesLeft); - display_symbol(0, LCD_SYMB_MAX, SEG_ON); + display_symbol(0, LCD_SYMB_MAX, SEG_ON); - } else { - /* show time till low */ - _printf(0, LCD_SEG_L1_3_2, "%02u", lowTide.hoursLeft); - _printf(0, LCD_SEG_L1_1_0, "%02u", lowTide.minutesLeft); + } else { + /* show time till low */ + _printf(0, LCD_SEG_L1_3_2, "%02u", lowTide.hoursLeft); + _printf(0, LCD_SEG_L1_1_0, "%02u", lowTide.minutesLeft); - display_symbol(0, LCD_UNIT_L2_MI, SEG_ON); - } - blinkCol(0, 1); - display_symbol(0, LCD_SEG_L2_COL1, SEG_ON); + display_symbol(0, LCD_UNIT_L2_MI, SEG_ON); + } + blinkCol(0, 1); + display_symbol(0, LCD_SEG_L2_COL1, SEG_ON); - /* line 2 graph */ - display_chars(0, LCD_SEG_L2_4_0, graphs[graphOffset], SEG_SET); + /* line 2 graph */ + display_chars(0, LCD_SEG_L2_4_0, graphs[graphOffset], SEG_SET); - /** screen 1 **/ - /* line 1 time till low */ - _printf(1, LCD_SEG_L1_3_2, "%02u", lowTide.hoursLeft); - _printf(1, LCD_SEG_L1_1_0, "%02u", lowTide.minutesLeft); + /** screen 1 **/ + /* line 1 time till low */ + _printf(1, LCD_SEG_L1_3_2, "%02u", lowTide.hoursLeft); + _printf(1, LCD_SEG_L1_1_0, "%02u", lowTide.minutesLeft); - display_symbol(1, LCD_UNIT_L2_MI, SEG_ON); + display_symbol(1, LCD_UNIT_L2_MI, SEG_ON); - /* line 2 calculate time of next high */ - uint16_t lowTideTimeInMinutes = (nowInMinutes + leftUntilLow) - % twentyFourHoursInMinutes; - struct Tide lowTideTime = timeFromMinutes(lowTideTimeInMinutes); + /* line 2 calculate time of next high */ + uint16_t lowTideTimeInMinutes = (nowInMinutes + leftUntilLow) + % twentyFourHoursInMinutes; + struct Tide lowTideTime = timeFromMinutes(lowTideTimeInMinutes); - _printf(1, LCD_SEG_L2_3_2, "%02u", lowTideTime.hoursLeft); - _printf(1, LCD_SEG_L2_1_0, "%02u", lowTideTime.minutesLeft); + _printf(1, LCD_SEG_L2_3_2, "%02u", lowTideTime.hoursLeft); + _printf(1, LCD_SEG_L2_1_0, "%02u", lowTideTime.minutesLeft); - blinkCol(1, 1); - blinkCol(1, 2); + blinkCol(1, 1); + blinkCol(1, 2); - /** screen 2 **/ - /* Line 1 time high */ - _printf(2, LCD_SEG_L1_3_2, "%02u", highTide.hoursLeft); - _printf(2, LCD_SEG_L1_1_0, "%02u", highTide.minutesLeft); - display_symbol(2, LCD_SYMB_MAX, SEG_ON); + /** screen 2 **/ + /* Line 1 time high */ + _printf(2, LCD_SEG_L1_3_2, "%02u", highTide.hoursLeft); + _printf(2, LCD_SEG_L1_1_0, "%02u", highTide.minutesLeft); + display_symbol(2, LCD_SYMB_MAX, SEG_ON); - /* line 2 calculate time of next high */ - uint16_t highTideTimeInMinutes = (nowInMinutes + leftUntilHigh) - % twentyFourHoursInMinutes; - struct Tide highTideTime = timeFromMinutes(highTideTimeInMinutes); + /* line 2 calculate time of next high */ + uint16_t highTideTimeInMinutes = (nowInMinutes + leftUntilHigh) + % twentyFourHoursInMinutes; + struct Tide highTideTime = timeFromMinutes(highTideTimeInMinutes); - _printf(2, LCD_SEG_L2_3_2, "%02u", highTideTime.hoursLeft); - _printf(2, LCD_SEG_L2_1_0, "%02u", highTideTime.minutesLeft); + _printf(2, LCD_SEG_L2_3_2, "%02u", highTideTime.hoursLeft); + _printf(2, LCD_SEG_L2_1_0, "%02u", highTideTime.minutesLeft); - blinkCol(2, 1); - blinkCol(2, 2); + blinkCol(2, 1); + blinkCol(2, 2); } /* MARK: System Bus Events */ void minuteTick() { - uint32_t tideInMinutes = timeInMinutes(tide); - graphOffset = (fullTideTime - tideInMinutes)/((uint16_t)186); - graphOffset = graphOffset % 4; - - /* count down the timer */ - if (tide.minutesLeft == 0) { - tide.minutesLeft = 60; - if (tide.hoursLeft == 0) { - /* TODO: change to full tide time */ - tide = timeFromMinutes(fullTideTime+1); - return; - } - tide.hoursLeft--; - } - tide.minutesLeft--; - - /* draw screens */ - drawScreen(); + uint32_t tideInMinutes = timeInMinutes(tide); + graphOffset = (fullTideTime - tideInMinutes) / ((uint16_t) 186); + graphOffset = graphOffset % 4; + + /* count down the timer */ + if (tide.minutesLeft == 0) { + tide.minutesLeft = 60; + if (tide.hoursLeft == 0) { + /* TODO: change to full tide time */ + tide = timeFromMinutes(fullTideTime + 1); + return; + } + tide.hoursLeft--; + } + tide.minutesLeft--; + + /* draw screens */ + drawScreen(); } /* MARK: - Time Setup */ void editHHSelect() { - display_chars(0, LCD_SEG_L1_3_2, NULL, BLINK_ON); + display_chars(0, LCD_SEG_L1_3_2, NULL, BLINK_ON); } void editHHDeselect(void) { - display_chars(0, LCD_SEG_L1_3_2, NULL, BLINK_OFF); + display_chars(0, LCD_SEG_L1_3_2, NULL, BLINK_OFF); } void editHHSet(int8_t step) { - helpers_loop(&(enteredTimeOfNextLow.hoursLeft), 0, 23, step); - _printf(0, LCD_SEG_L1_3_2, "%02u", enteredTimeOfNextLow.hoursLeft); + helpers_loop(&(enteredTimeOfNextLow.hoursLeft), 0, 23, step); + _printf(0, LCD_SEG_L1_3_2, "%02u", enteredTimeOfNextLow.hoursLeft); } void editMMSelect(void) { - display_chars(0, LCD_SEG_L1_1_0, NULL, BLINK_ON); + display_chars(0, LCD_SEG_L1_1_0, NULL, BLINK_ON); } void editMMDeselect(void) { - display_chars(0, LCD_SEG_L1_1_0, NULL, BLINK_OFF); + display_chars(0, LCD_SEG_L1_1_0, NULL, BLINK_OFF); } void editMMSet(int8_t step) { - helpers_loop(&(enteredTimeOfNextLow.minutesLeft), 0, 59, step); - _printf(0, LCD_SEG_L1_1_0, "%02u", enteredTimeOfNextLow.minutesLeft); + helpers_loop(&(enteredTimeOfNextLow.minutesLeft), 0, 59, step); + _printf(0, LCD_SEG_L1_1_0, "%02u", enteredTimeOfNextLow.minutesLeft); } static struct menu_editmode_item editModeItems[] = { - {&editHHSelect, &editHHDeselect, &editHHSet}, - {&editMMSelect, &editMMDeselect, &editMMSet}, - { NULL } + {&editHHSelect, &editHHDeselect, &editHHSet}, + {&editMMSelect, &editMMDeselect, &editMMSet}, + {NULL} }; void endEditing(void) { - /* calculate minutes left for next low */ - uint16_t nextLowMinutes = timeInMinutes(enteredTimeOfNextLow); - uint16_t nowInMinutes = timeNowInMinutes(); - uint16_t diff = nextLowMinutes - nowInMinutes; - if (diff < 0) { - /* the next low is tomorrow! */ - diff = (twentyFourHoursInMinutes - nowInMinutes) + nextLowMinutes; - } - - tide = timeFromMinutes(diff); - editModeActivated = 0; - display_clear(0, 0); - drawScreen(); + /* calculate minutes left for next low */ + uint16_t nextLowMinutes = timeInMinutes(enteredTimeOfNextLow); + uint16_t nowInMinutes = timeNowInMinutes(); + uint16_t diff = nextLowMinutes - nowInMinutes; + if (diff < 0) { + /* the next low is tomorrow! */ + diff = (twentyFourHoursInMinutes - nowInMinutes) + nextLowMinutes; + } + + tide = timeFromMinutes(diff); + editModeActivated = 0; + display_clear(0, 0); + drawScreen(); } /* MARK: - Buttons */ void longStarButton(void) { - /* clear screen */ - display_clear(0, 0); - lcd_screen_activate(0); - - uint16_t nowInMinutes = timeNowInMinutes(); - uint16_t leftUntilLow = timeInMinutes(tide); - enteredTimeOfNextLow = timeFromMinutes((nowInMinutes + leftUntilLow) % twentyFourHoursInMinutes); - - editModeActivated = 1; - _printf(0, LCD_SEG_L1_3_2, "%02u", enteredTimeOfNextLow.hoursLeft); - _printf(0, LCD_SEG_L1_1_0, "%02u", enteredTimeOfNextLow.minutesLeft); - blinkCol(0, 1); - menu_editmode_start(&endEditing, NULL, editModeItems); + /* clear screen */ + display_clear(0, 0); + lcd_screen_activate(0); + + uint16_t nowInMinutes = timeNowInMinutes(); + uint16_t leftUntilLow = timeInMinutes(tide); + enteredTimeOfNextLow = + timeFromMinutes((nowInMinutes + + leftUntilLow) % twentyFourHoursInMinutes); + + editModeActivated = 1; + _printf(0, LCD_SEG_L1_3_2, "%02u", enteredTimeOfNextLow.hoursLeft); + _printf(0, LCD_SEG_L1_1_0, "%02u", enteredTimeOfNextLow.minutesLeft); + blinkCol(0, 1); + menu_editmode_start(&endEditing, NULL, editModeItems); } void buttonUp(void) { - lcd_screen_activate(0xff); - drawScreen(); + lcd_screen_activate(0xff); + drawScreen(); } void buttonDown(void) { - if (activeDisplay <= 0) - activeDisplay = 2; - else - activeDisplay = (activeDisplay - 1) % 3; + if (activeDisplay <= 0) + activeDisplay = 2; + else + activeDisplay = (activeDisplay - 1) % 3; - lcd_screen_activate(activeDisplay); - drawScreen(); + lcd_screen_activate(activeDisplay); + drawScreen(); } /* MARK: - Activate and Deactivate */ void activate(void) { - moduleActivated = 1; - /* create three empty screens */ - lcd_screens_create(3); + moduleActivated = 1; + /* create three empty screens */ + lcd_screens_create(3); - activeDisplay = TIDE_DISPLAY_STATE_GRAPH; - lcd_screen_activate(activeDisplay); - drawScreen(); + activeDisplay = TIDE_DISPLAY_STATE_GRAPH; + lcd_screen_activate(activeDisplay); + drawScreen(); } void deactivate(void) { - moduleActivated = 0; - /* destroy virtual screens */ - lcd_screens_destroy(); + moduleActivated = 0; + /* destroy virtual screens */ + lcd_screens_destroy(); - display_clear(0, 0); + display_clear(0, 0); } void mod_tide_init(void) { - sys_messagebus_register(&minuteTick, SYS_MSG_RTC_MINUTE); - menu_add_entry("TIDE", - &buttonUp, - &buttonDown, - NULL, - &longStarButton, - NULL, - NULL, - &activate, - &deactivate); - tide = timeFromMinutes(90); /* fullTideTime); */ - minuteTick(); /* initla display setup */ + sys_messagebus_register(&minuteTick, SYS_MSG_RTC_MINUTE); + menu_add_entry("TIDE", + &buttonUp, + &buttonDown, + NULL, + &longStarButton, NULL, NULL, &activate, &deactivate); + tide = timeFromMinutes(90); /* fullTideTime); */ + minuteTick(); /* initla display setup */ } diff --git a/modules/tide.cfg b/modules/tide.cfg index 02f47fc..44371b5 100644 --- a/modules/tide.cfg +++ b/modules/tide.cfg @@ -1,4 +1,4 @@ [TIDE] -menu_order = 90 +menu_order = 4 name = Tide [EXPERIMENTAL] -help = a Tide Watch +help = a Tide Watch \ No newline at end of file diff --git a/openchronos.c b/openchronos.c index 0b4cf1f..ad6161f 100644 --- a/openchronos.c +++ b/openchronos.c @@ -71,8 +71,9 @@ /* Driver */ #include "drivers/display.h" -#include "drivers/vti_as.h" -#include "drivers/vti_ps.h" +#include "drivers/as.h" +#include "drivers/bmp_ps.h" +#include "drivers/ps.h" #include "drivers/radio.h" #include "drivers/buzzer.h" #include "drivers/ports.h" @@ -86,43 +87,57 @@ #include "drivers/wdt.h" #include "drivers/lpm.h" +#if defined (WHITE_PCB) && defined (BLACK_PCB) +#error "You can't use both Black and White modules!" +#endif +#ifdef WHITE_PCB +#include "drivers/bmp_as.h" +#endif +#ifdef BLACK_PCB +#include "drivers/vti_as.h" +#endif void handle_events(void) { enum sys_message msg = SYS_MSG_NONE; /* drivers/rtca */ if (rtca_last_event) { - msg |= rtca_last_event; - rtca_last_event = RTCA_EV_NONE; + msg |= rtca_last_event; + rtca_last_event = RTCA_EV_NONE; } /* drivers/timer */ if (timer0_last_event) { - msg |= timer0_last_event << 7; - timer0_last_event = TIMER0_EVENT_NONE; + msg |= timer0_last_event << 7; + timer0_last_event = TIMER0_EVENT_NONE; } /* drivers/accelerometer */ - if(as_last_interrupt){ - msg |= SYS_MSG_AS_INT; - as_last_interrupt = 0; + if (as_last_interrupt) { + msg |= SYS_MSG_AS_INT; + as_last_interrupt = 0; + } + + /* drivers/pressure */ + if (ps_last_interrupt) { + msg |= SYS_MSG_PS_INT; + ps_last_interrupt = 0; } /* menu system */ if (msg & SYS_MSG_RTC_SECOND) { - menu_timeout_poll(); + menu_timeout_poll(); } - #ifdef CONFIG_BATTERY_MONITOR /* drivers/battery */ if (msg & SYS_MSG_RTC_MINUTE) { - msg |= SYS_MSG_BATT; - battery_measurement(); + msg |= SYS_MSG_BATT; + battery_measurement(); } #endif if (is_ports_button_pressed()) { - msg |= SYS_MSG_BUTTON; + msg |= SYS_MSG_BUTTON; } send_events(msg); @@ -178,12 +193,12 @@ void init_application(void) radio_reset(); radio_powerdown(); -#ifdef CONFIG_MOD_ACCELEROMETER +#if defined(CONFIG_MOD_ACCELEROMETER_B) || defined(CONFIG_MOD_ACCELEROMETER_W) // --------------------------------------------------------------------- // Init acceleration sensor as_init(); #else - as_disconnect(); + //as_disconnect(); #endif // --------------------------------------------------------------------- @@ -209,14 +224,15 @@ void init_application(void) #ifdef CONFIG_INFOMEM if (infomem_ready() == -2) { - infomem_init(INFOMEM_C, INFOMEM_C + 2 * INFOMEM_SEGMENT_SIZE); + infomem_init(INFOMEM_C, INFOMEM_C + 2 * INFOMEM_SEGMENT_SIZE); } #endif } #ifdef CONFIG_RUNLOOP_INDICATOR -void debug_runloop_indicator() { - static uint8_t is_on; // Dirty, but keeps it local. +void debug_runloop_indicator() +{ + static uint8_t is_on; // Dirty, but keeps it local. is_on ^= 1; display_symbol(0, LCD_ICON_HEART, is_on ? SEG_ON : SEG_OFF); } @@ -241,62 +257,63 @@ int main(void) /* main loop */ while (1) { - /* Go to LPM3, wait for interrupts */ - enter_lpm_gie(LPM3_bits); + /* Go to LPM3, wait for interrupts */ + enter_lpm_gie(LPM3_bits); #ifdef CONFIG_RUNLOOP_INDICATOR - debug_runloop_indicator(); + debug_runloop_indicator(); #endif - /* service watchdog on wakeup */ - wdt_poll(); + /* service watchdog on wakeup */ + wdt_poll(); - /* poll the button driver */ - ports_buttons_poll(); + /* poll the button driver */ + ports_buttons_poll(); - /* check if any driver has events pending */ - handle_events(); + /* check if any driver has events pending */ + handle_events(); - /* check for button presses and drive the menu */ - menu_check_buttons(); + /* check for button presses and drive the menu */ + menu_check_buttons(); } } /*************************************************************************** **************************** HERE BE HELPERS ****************************** **************************************************************************/ -void helpers_loop(uint8_t *value, uint8_t lower, uint8_t upper, int8_t step) +void helpers_loop(uint8_t * value, uint8_t lower, uint8_t upper, + int8_t step) { /* Ensure that initial value is between lower and upper interval */ if (*value > upper) { - *value = upper; + *value = upper; } if (*value < lower) { - *value = lower; + *value = lower; } /* for now only increase/decrease on steps of 1 value */ if (step > 0) { - /* prevent overflow */ - if (*value == 255) { - *value = lower; - return; - } + /* prevent overflow */ + if (*value == 255) { + *value = lower; + return; + } - (*value)++; + (*value)++; - if(*value - 1 == upper) - *value = lower; + if (*value - 1 == upper) + *value = lower; } else { - /* prevent overflow */ - if (*value == 0) { - *value = upper; - return; - } - - (*value)--; - if(*value + 1 == lower) - *value = upper; + /* prevent overflow */ + if (*value == 0) { + *value = upper; + return; + } + + (*value)--; + if (*value + 1 == lower) + *value = upper; } } diff --git a/openchronos.h b/openchronos.h index 9cd8e7f..722528e 100644 --- a/openchronos.h +++ b/openchronos.h @@ -59,7 +59,7 @@ /*! \brief Handy prototype typedef for helpers_loop() function. */ -typedef void(* helpers_loop_fn_t)(uint8_t *, uint8_t, uint8_t, int8_t); +typedef void (*helpers_loop_fn_t) (uint8_t *, uint8_t, uint8_t, int8_t); /*! \brief Increment/decrements value by one without exiting the [lower, upper] interval. @@ -67,11 +67,10 @@ typedef void(* helpers_loop_fn_t)(uint8_t *, uint8_t, uint8_t, int8_t); Note: For now, only steps of -1 and 1 are considered. \sa menu_editmode_start */ -void helpers_loop( - uint8_t *value, /*!< value a pointer to the variable to be incremented. */ - uint8_t lower, /*!< lower the lower bound for the loop interval. */ - uint8_t upper, /*!< upper the upper bound for the loop interval. */ - int8_t step /*!< 1 for incrementing value, -1 for a decrement */ -); - -#endif /* __EZCHRONOS_H__ */ +void helpers_loop(uint8_t * value, /*!< value a pointer to the variable to be incremented. */ + uint8_t lower, /*!< lower the lower bound for the loop interval. */ + uint8_t upper, /*!< upper the upper bound for the loop interval. */ + int8_t step /*!< 1 for incrementing value, -1 for a decrement */ + ); + +#endif /* __EZCHRONOS_H__ */ diff --git a/tools/config.py b/tools/config.py index 41be55a..ca06b08 100644 --- a/tools/config.py +++ b/tools/config.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # encoding: utf-8 # vim: ts=4 noexpandtab @@ -22,16 +22,28 @@ "type": "info", } +DATA["WHITE_PCB"] = { + "name": "Use White PCB modules", + "default": False, + "help": "Enables modules written for White PCB (newer) watches." +} + +DATA["BLACK_PCB"] = { + "name": "Use Black PCB modules", + "default": True, + "help": "Enables modules written for Black PCB (older) watches." +} + DATA["CONFIG_DEBUG"] = { "name": "Build debug code", "default": False, - "help": "Sets CFLAGS and LDFLAGS for debugging", + "help": "Sets CFLAGS and LDFLAGS for debugging.", } DATA["USE_LCD_CHARGE_PUMP"] = { "name": "Use LCD Charge Pump (6 bytes)", "default": False, - "help": "Use the internal charge pump to make the display contrast contstant through the whole battery lifetime. As a downside this increases currency and reduces battery lifetime.", + "help": "Use the internal charge pump to make the display contrast constant through the whole battery lifetime. As a downside this increases current usage and reduces battery lifetime.", } DATA["USE_WATCHDOG"] = { @@ -43,7 +55,7 @@ DATA["CONFIG_RUNLOOP_INDICATOR"] = { "name": "Show runloop indicator", "default": False, - "help": "Enable or disable the runloop indicator (heart symbol blinks at each runloop)", + "help": "Enable or disable the runloop indicator (heart symbol blinks at each runloop).", } # RTC DRIVER ################################################################# @@ -56,14 +68,14 @@ DATA["CONFIG_RTC_IRQ"] = { "name": "Enable RTC interrupts", "default": True, - "help": "Enables interrupts on the Real Time Clock", + "help": "Enables interrupts on the Real Time Clock.", } DATA["CONFIG_RTC_DST"] = { "name": "DST", "default": False, 'depends': [ 'CONFIG_RTC_IRQ' ], - "help": "Automatically adjusts real-time clock for daylight savings time", + "help": "Automatically adjusts real-time clock for daylight savings time.", } DATA["CONFIG_RTC_DST_ZONE"] = { @@ -71,7 +83,7 @@ "type": "text", "default": 1, 'depends': [ 'CONFIG_RTC_DST' ], - "help": "DST Zone: 1=DST_US, 2=DST_MEX, 3=DST_BRZ, 4=DST_EU, 5=DST_AUS, 6=DST_NZ" + "help": "DST Zone: 1=DST_US, 2=DST_MEX, 3=DST_BRZ, 4=DST_EU, 5=DST_AUS, 6=DST_NZ." } # TIMER0 DRIVER ############################################################## @@ -84,7 +96,7 @@ DATA["CONFIG_TIMER_4S_IRQ"] = { "name": "Enable 0.244Hz timer interrupts", "default": False, - "help": "Enables 0.244Hz interrupts on the hardware timer", + "help": "Enables 0.244Hz interrupts on the hardware timer.", } # PORTS DRIVER ############################################################### @@ -99,7 +111,7 @@ "type": "text", "default": "20", "ifndef": True, - "help": "Long button press time (in multiples of 1/20 second)", + "help": "Long button press time (in multiples of 1/20 second).", } DATA["CONFIG_BUTTONS_SHORT_PRESS_TIME"] = { @@ -107,7 +119,7 @@ "type": "text", "default": "1", "ifndef": True, - "help": "Short button press time (in multiples of 1/20 second)", + "help": "Short button press time (in multiples of 1/20 second).", } DATA["CONFIG_BUTTONS_SWAP_UP_AND_DOWN"] = { @@ -115,7 +127,7 @@ "type": "bool", "default": False, "ifndef": False, - "help": "When set up means previous/-1 and down means next/+1", + "help": "When set up means previous/-1 and down means next/+1.", } # BATTERY DRIVER ############################################################# @@ -150,7 +162,7 @@ "type": "text", "default": "-260", "ifndef": True, - "help": "Compensate the sensor raw output value with this offset", + "help": "Compensate the sensor raw output value with this offset.", } DATA["CONFIG_TEMPERATURE_METRIC"] = { @@ -159,6 +171,19 @@ "help": "Show in degrees C if enabled, F otherwise.", } +# RADIO DRIVER ################################################## +DATA["TEXT_RADIO"] = { + "name": "Radio driver", + "type": "info", +} + +DATA["CONFIG_ISM"] = { + "name": "ISM band for radio operation", + "type": "text", + "default": 1, + "help": "Band: 1=US (902MHz), 2=EU (868MHz), 3=LF (433MHz legacy)." +} + # AUTOMATICALLY GENERATED MODULE LIST ######################################## DATA["TEXT_MODULES"] = { @@ -255,7 +280,7 @@ class OpenChronosApp(object): def main(self): global DATA - text_header = (u"OpenChronos config \u2503 " + text_header = (u"OpenChronos config - " u"UP / DOWN / PAGE UP / PAGE DOWN scroll. F8 aborts.") self.list_content = list_content = [] @@ -282,7 +307,7 @@ def ok_pressed(*args, **kwargs): def abort_pressed(*args, **kwargs): sys.exit(0) - list_content.append(urwid.Divider(div_char=u"\u2550", top=1, bottom=1)) + list_content.append(urwid.Divider(div_char=u"-", top=1, bottom=1)) list_content.append( urwid.Padding(urwid.GridFlow( [urwid.AttrWrap(urwid.Button("Save", ok_pressed), 'opt','optsel'),