diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..270f8cf77 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.o +doc/doxygen/html +doc/doxygen/latex +doc/doxygen/man +*bin diff --git a/Jamfile b/Jamfile index 3c442afa9..3e199228c 100644 --- a/Jamfile +++ b/Jamfile @@ -67,8 +67,8 @@ Debug debug : $(TARGET) ; ListModules listmodules ; ShowFlags showflags : $(TARGET) ; -SubInclude TOP projects $(PROJECT) ; SubInclude TOP sys ; SubInclude TOP core ; SubInclude TOP drivers ; SubInclude TOP board ; +SubInclude TOP projects $(PROJECT) ; diff --git a/Jamrules b/Jamrules index 8eca19afc..12568ea8d 100644 --- a/Jamrules +++ b/Jamrules @@ -31,15 +31,15 @@ include $(TOP)$(SLASH)Jamrules.common ; # -# Setup FeuerWare build system configuration (default values for common options) +# Setup ukleos build system configuration (default values for common options) # -PROJECT = $(PROJECT:E=hello-world) ; +PROJECT = $(PROJECT:E=default) ; BOARD = $(BOARD:E=msba2) ; SUFFIX ?= "" ; # must be at least "" !!! TARGET = "$(BOARD)-$(PROJECT)$(SUFFIX)$(SUFEXE)" ; # main target binary OPENOCD_IF ?= olimex-jtag-tiny-a ; -TERMINAL ?= board/msba2/tools/bin/pseudoterm ; +TERMINAL ?= tools/pyterm/pyterm.py ; if $(NT) || $(OS) = CYGWIN { PORT = $(PORT:E=1) ; @@ -53,7 +53,6 @@ CCFLAGS += -DBOARD=BOARD_$(BOARD:U) ; # core source directories HDRS += $(TOP) ; HDRS += [ FPath $(TOP) core include ] ; -HDRS += [ FPath $(TOP) hal include ] ; HDRS += [ FPath $(TOP) sys include ] [ FPath $(TOP) sys config ] [ FPath $(TOP) sys drivers include ] [ FPath $(TOP) sys drivers cc110x ] [ FPath $(TOP) sys drivers nanopan5375 ] ; HDRS += [ FPath $(TOP) sys net ] ; HDRS += [ FPath $(TOP) sys lib ] [ FPath $(TOP) sys lib fat include ] ; @@ -74,3 +73,4 @@ HDRS += [ FPath $(TOP) projects $(PROJECT) ] ; # drivers HDRS += [ FPath $(TOP) drivers include ] ; HDRS += [ FPath $(TOP) drivers cc110x ] ; +HDRS += [ FPath $(TOP) drivers cc110x_ng include ] ; diff --git a/Jamrules.common b/Jamrules.common index d92882466..7ad058b04 100644 --- a/Jamrules.common +++ b/Jamrules.common @@ -125,7 +125,7 @@ actions Cleanall { echo "> Cleaning binaries" $(RM) bin$(SLASH)* - make -C $(TOP)$(SLASH)doc clean +# make -C $(TOP)$(SLASH)doc clean } # @@ -177,7 +177,7 @@ rule Test } actions Test { - for tst in projects/$(PROJECT)/tests/*; do $tst; done + export PORT=$(PORT); for tst in projects/$(PROJECT)/tests/*; do $tst; done } # Reset connected sensor node @@ -357,4 +357,3 @@ actions ShowFlags { echo "" | $(CC) -E -dD - } - diff --git a/README b/README index aed49aaf3..44f24ab49 100644 --- a/README +++ b/README @@ -7,3 +7,4 @@ License a separate license. All code files contain licensing information. + diff --git a/board/eZ430-Chronos/Jamfile b/board/chronos/Jamfile similarity index 62% rename from board/eZ430-Chronos/Jamfile rename to board/chronos/Jamfile index ea723c95a..0899e4631 100644 --- a/board/eZ430-Chronos/Jamfile +++ b/board/chronos/Jamfile @@ -1,8 +1,8 @@ -SubDir TOP board eZ430-Chronos ; +SubDir TOP board chronos ; HDRS += $(TOP)/board/$(CPU)/include ; -Module board : debug_uart.c board_init.c ; +Module board : putchar.c board_init.c ; UseModule board ; SubInclude TOP board $(BOARD) drivers ; diff --git a/board/eZ430-Chronos/Jamrules.eZ430-Chronos b/board/chronos/Jamrules.chronos similarity index 77% rename from board/eZ430-Chronos/Jamrules.eZ430-Chronos rename to board/chronos/Jamrules.chronos index eef3a0301..4c17a9a9a 100644 --- a/board/eZ430-Chronos/Jamrules.eZ430-Chronos +++ b/board/chronos/Jamrules.chronos @@ -3,10 +3,12 @@ # ****************************************************************************** # $Id$ -BOARD = eZ430-Chronos ; -CPU = msp430 ; +BOARD = chronos ; +CPU = cc430 ; MCU = cc430x6137 ; +HDRS += [ FPath $(TOP) board chronos drivers include ] ; + FLASHER ?= mspdebug ; FLASHFLAGS ?= rf2500 ; diff --git a/board/chronos/board_init.c b/board/chronos/board_init.c new file mode 100644 index 000000000..74799abac --- /dev/null +++ b/board/chronos/board_init.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include + +void cc430_cpu_init(void) { + volatile uint16_t i; + volatile unsigned char *ptr; + + /* disable watchdog */ + WDTCTL = WDTPW + WDTHOLD; + + // --------------------------------------------------------------------- + // Enable 32kHz ACLK + P5SEL |= 0x03; // Select XIN, XOUT on P5.0 and P5.1 + UCSCTL6 &= ~XT1OFF; // XT1 On, Highest drive strength + UCSCTL6 |= XCAP_3; // Internal load cap + + UCSCTL3 = SELA__XT1CLK; // Select XT1 as FLL reference + UCSCTL4 = SELA__XT1CLK | SELS__DCOCLKDIV | SELM__DCOCLKDIV; + + // --------------------------------------------------------------------- + // Configure CPU clock for 12MHz + _BIS_SR(SCG0); // Disable the FLL control loop + UCSCTL0 = 0x0000; // Set lowest possible DCOx, MODx + UCSCTL1 = DCORSEL_5; // Select suitable range + UCSCTL2 = FLLD_1 + 0x16E; // Set DCO Multiplier + _BIC_SR(SCG0); // Enable the FLL control loop + + // 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 8 MHz / 32,768 Hz = 250000 = MCLK cycles for DCO to settle + for (i = 0xFF; i > 0; i--); // Time for flag to set + + // Loop until XT1 & DCO stabilizes, use do-while to insure that + // body is executed at least once + do + { + UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + XT1HFOFFG + DCOFFG); + SFRIFG1 &= ~OFIFG; // Clear fault flags + } while ((SFRIFG1 & OFIFG)); + + // Disable all interrupts + __disable_interrupt(); + // Get write-access to port mapping registers: + PMAPPWD = 0x02D52; + // Allow reconfiguration during runtime: + PMAPCTL = PMAPRECFG; + + // P2.7 = TA0CCR1A or TA1CCR0A output (buzzer output) + ptr = &P2MAP0; + *(ptr+7) = PM_TA1CCR0A; + P2OUT &= ~BIT7; + P2DIR |= BIT7; + + // P1.5 = SPI MISO input + ptr = &P1MAP0; + *(ptr+5) = PM_UCA0SOMI; + // P1.6 = SPI MOSI output + *(ptr+6) = PM_UCA0SIMO; + // P1.7 = SPI CLK output + *(ptr+7) = PM_UCA0CLK; + + // Disable write-access to port mapping registers: + PMAPPWD = 0; + // Re-enable all interrupts + enableIRQ(); + +} + +void board_init() { + cc430_cpu_init(); +} diff --git a/board/chronos/drivers/Jamfile b/board/chronos/drivers/Jamfile new file mode 100644 index 000000000..71ee1c982 --- /dev/null +++ b/board/chronos/drivers/Jamfile @@ -0,0 +1,11 @@ +SubDir TOP board chronos drivers ; + +HDRS += $(TOP)/board/$(CPU)/drivers/include ; + +Module board_display : display.c display1.c ; +Module board_cc110x : cc430-cc110x.c : cc110x_cc430 ; +Module board_buzzer : buzzer.c : hwtimer ; +Module battery : battery.c : adc hwtimer ; +Module vti_ps_twi : vti_ps_twi.c : hwtimer ; + +Module display_putchar : display_putchar.c : board_display ; diff --git a/board/chronos/drivers/battery.c b/board/chronos/drivers/battery.c new file mode 100644 index 000000000..bae37d329 --- /dev/null +++ b/board/chronos/drivers/battery.c @@ -0,0 +1,13 @@ +#include +#include +#include + +uint32_t battery_get_voltage(void) { + uint32_t voltage; + voltage = adc12_single_conversion(REFVSEL_1, ADC12SHT0_10, ADC12INCH_11); + + /* 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 * 2 * 1000) / 4095; + return voltage; +} diff --git a/board/chronos/drivers/buzzer.c b/board/chronos/drivers/buzzer.c new file mode 100644 index 000000000..5e0bc2ca3 --- /dev/null +++ b/board/chronos/drivers/buzzer.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +void buzzer_beep(uint8_t pitch, uint16_t duration) { + // Reset TA1R, set up mode, TA1 runs from 32768Hz ACLK + TA1CTL = TACLR | MC_1 | TASSEL__ACLK; + + // Set PWM frequency + TA1CCR0 = pitch; + + // Enable IRQ, set output mode "toggle" + TA1CCTL0 = OUTMOD_4; + + // Allow buzzer PWM output on P2.7 + P2SEL |= BIT7; + + hwtimer_wait(duration); + + // Stop PWM timer + TA1CTL &= ~(BIT4 | BIT5); + + // Reset and disable buzzer PWM output + P2OUT &= ~BIT7; + P2SEL &= ~BIT7; + TA1CCTL0 &= ~CCIE; +} diff --git a/board/chronos/drivers/cc430-cc110x.c b/board/chronos/drivers/cc430-cc110x.c new file mode 100644 index 000000000..78380c4ca --- /dev/null +++ b/board/chronos/drivers/cc430-cc110x.c @@ -0,0 +1,81 @@ +#include + +#include +#include +#include +#include + +//#include +#include +//#include + +#define CC1100_GDO0 (RF1AIN & BIT0) +#define CC1100_GDO1 (RF1AIN & BIT1) +#define CC1100_GDO2 (RF1AIN & BIT2) + +int cc110x_get_gdo0(void) { + return CC1100_GDO0; +} + +int cc110x_get_gdo1(void) { + return CC1100_GDO1; +} + +int cc110x_get_gdo2(void) { + return CC1100_GDO2; +} + +void cc110x_before_send(void) +{ + // Disable GDO2 interrupt before sending packet + cc110x_gdo2_disable(); +} + +void cc110x_after_send(void) +{ + // Enable GDO2 interrupt after sending packet + cc110x_gdo2_enable(); +} + +void cc110x_gdo0_enable(void) { + RF1AIFG &= ~BIT0; + RF1AIE |= BIT0; +} + +void cc110x_gdo0_disable(void) { + RF1AIE &= ~BIT0; + RF1AIFG &= ~BIT0; +} + +void cc110x_gdo2_disable(void) { + RF1AIFG &= ~BIT2; // Clear a pending interrupt + RF1AIE &= ~BIT2; // Disable the interrupt +} + +void cc110x_gdo2_enable(void) { + RF1AIFG &= ~BIT2; // Clear a pending interrupt + RF1AIE |= BIT2; // Enable the interrupt +} + +void cc110x_init_interrupts(void) { + uint8_t state = disableIRQ(); /* Disable all interrupts */ + cc110x_gdo2_enable(); + cc110x_gdo0_disable(); + restoreIRQ(state); /* Enable all interrupts */ +} + +interrupt (CC1101_VECTOR) __attribute__ ((naked)) cc110x_isr(void){ + __enter_isr(); + /* Check IFG */ + if (RF1AIV == RF1AIV_RFIFG2) { + while (RF1AIN & BIT2); + /* discard all further interrupts */ + RF1AIV = 0; + cc110x_gdo2_irq(); + } + if (RF1AIV == RF1AIV_RFIFG0) { + cc110x_gdo0_irq(); + RF1AIE &= ~BIT0; + } + __exit_isr(); +} diff --git a/board/chronos/drivers/display.c b/board/chronos/drivers/display.c new file mode 100644 index 000000000..063ade585 --- /dev/null +++ b/board/chronos/drivers/display.c @@ -0,0 +1,383 @@ +/* ************************************************************************************************* + * + * 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. + * + * ************************************************************************************************* + * Basic display functions. + * ************************************************************************************************/ + +/* ************************************************************************************************* + * Include section + */ + +/* system */ +#include + +/* driver */ +#include +#include + + +/************************************************************************************************** + * Prototypes section */ +void write_lcd_mem(uint8_t *lcdmem, uint8_t bits, uint8_t bitmask, uint8_t state); +void clear_line(uint8_t line); +void display_symbol(uint8_t symbol, uint8_t mode); + +/* ************************************************************************************************* + * Global Variable section */ + +/* Display flags */ +volatile s_display_flags_t display; + +/* Global return string for itoa function */ +char itoa_str[8]; + +void lcd_init(void) { + /* Clear entire display memory */ + LCDBMEMCTL |= LCDCLRBM + LCDCLRM; + + /* LCD_FREQ = ACLK/16/8 = 256Hz */ + /* Frame frequency = 256Hz/4 = 64Hz, LCD mux 4, LCD on */ + LCDBCTL0 = (LCDDIV0 + LCDDIV1 + LCDDIV2 + LCDDIV3) | (LCDPRE0 + LCDPRE1) | LCD4MUX | LCDON; + + /* LCB_BLK_FREQ = ACLK/8/4096 = 1Hz */ + LCDBBLKCTL = LCDBLKPRE0 | LCDBLKPRE1 | LCDBLKDIV0 | LCDBLKDIV1 | LCDBLKDIV2 | LCDBLKMOD0; + + /* I/O to COM outputs */ + P5SEL |= (BIT5 | BIT6 | BIT7); + P5DIR |= (BIT5 | BIT6 | BIT7); + + /* Activate LCD output */ + LCDBPCTL0 = 0xFFFF; /* Select LCD segments S0-S15 */ + LCDBPCTL1 = 0x00FF; /* Select LCD segments S16-S22 */ + +#ifdef USE_LCD_CHARGE_PUMP + /* Charge pump voltage generated internally, internal bias (V2-V4) generation */ + LCDBVCTL = LCDCPEN | VLCD_2_72; +#endif +} + +void clear_display_all(void) { + // Clear generic content + clear_line(LINE1); + clear_line(LINE2); +} + +void clear_display(void) { + clear_line(LINE1); + clear_line(LINE2); +} + +void clear_line(uint8_t line) { + display_chars(switch_seg(line, LCD_SEG_L1_3_0, LCD_SEG_L2_5_0), NULL, SEG_OFF); + if (line == LINE1) { + display_symbol(LCD_SEG_L1_DP1, SEG_OFF); + display_symbol(LCD_SEG_L1_DP0, SEG_OFF); + display_symbol(LCD_SEG_L1_COL, SEG_OFF); + } + /* line == LINE2 */ + else { + display_symbol(LCD_SEG_L2_DP, SEG_OFF); + display_symbol(LCD_SEG_L2_COL1, SEG_OFF); + display_symbol(LCD_SEG_L2_COL0, SEG_OFF); + } +} + +void write_lcd_mem(uint8_t *lcdmem, uint8_t bits, uint8_t bitmask, uint8_t state) { + if (state == SEG_ON) { + /* Clear segments before writing */ + *lcdmem = (uint8_t)(*lcdmem & ~bitmask); + + /* Set visible segments */ + *lcdmem = (uint8_t)(*lcdmem | bits); + } + else if (state == SEG_OFF) { + /* Clear segments */ + *lcdmem = (uint8_t)(*lcdmem & ~bitmask); + } + else if (state == SEG_ON_BLINK_ON) { + /* Clear visible / blink segments before writing */ + *lcdmem = (uint8_t)(*lcdmem & ~bitmask); + *(lcdmem+0x20) = (uint8_t)(*(lcdmem+0x20) & ~bitmask); + + /* Set visible / blink segments */ + *lcdmem = (uint8_t)(*lcdmem | bits); + *(lcdmem+0x20) = (uint8_t)(*(lcdmem+0x20) | bits); + } + else if (state == SEG_ON_BLINK_OFF) { + /* Clear visible segments before writing */ + *lcdmem = (uint8_t)(*lcdmem & ~bitmask); + + /* Set visible segments */ + *lcdmem = (uint8_t)(*lcdmem | bits); + + /* Clear blink segments */ + *(lcdmem+0x20) = (uint8_t)(*(lcdmem+0x20) & ~bitmask); + } + else if (state == SEG_OFF_BLINK_OFF) { + /* Clear segments */ + *lcdmem = (uint8_t)(*lcdmem & ~bitmask); + + /* Clear blink segments */ + *(lcdmem+0x20) = (uint8_t)(*(lcdmem+0x20) & ~bitmask); + } +} + +char *itoa(uint32_t n, uint8_t digits, uint8_t blanks) { + uint8_t i; + uint8_t digits1 = digits; + + /* Preset result string */ + memcpy(itoa_str, "0000000", 7); + + /* Return empty string if number of digits is invalid (valid range for digits: 1-7) */ + if ((digits == 0) || (digits > 7)) { + return (itoa_str); + } + + /* Numbers 0 .. 180 can be copied from itoa_conversion_table without conversion */ + if (n <= 180) { + if (digits >= 3) { + memcpy(itoa_str+(digits-3), itoa_conversion_table[n], 3); + } + /* digits == 1 || 2 */ + else { + memcpy(itoa_str, itoa_conversion_table[n]+(3-digits), digits); + } + } + /* For n > 180 need to calculate string content */ + else { + /* Calculate digits from least to most significant number */ + do { + itoa_str[digits-1] = n % 10 + '0'; + n /= 10; + } while (--digits > 0); + } + + /* Remove specified number of leading '0', always keep last one */ + i = 0; + while ((itoa_str[i] == '0') && (i < digits1-1)) { + if (blanks > 0) { + /* Convert only specified number of leading '0' */ + itoa_str[i]=' '; + blanks--; + } + i++; + } + return (itoa_str); +} + +void display_value1(uint8_t segments, uint32_t value, uint8_t digits, uint8_t blanks, uint8_t disp_mode) { + char *str; + + str = itoa(value, digits, blanks); + + /* Display string in blink mode */ + display_chars(segments, str, disp_mode); +} + +void display_symbol(uint8_t symbol, uint8_t mode) { + uint8_t *lcdmem; + uint8_t bits; + uint8_t bitmask; + + if (symbol <= LCD_SEG_L2_DP) { + /* Get LCD memory address for symbol from table */ + lcdmem = (uint8_t*)segments_lcdmem[symbol]; + + /* Get bits for symbol from table */ + bits = segments_bitmask[symbol]; + + /* Bitmask for symbols equals bits */ + bitmask = bits; + + /* Write LCD memory */ + write_lcd_mem(lcdmem, bits, bitmask, mode); + } +} + +void display_char(uint8_t segment, char chr, uint8_t mode) { + uint8_t *lcdmem; /* Pointer to LCD memory */ + uint8_t bitmask; /* Bitmask for character */ + uint8_t bits, bits1; /* Bits to write */ + + /* 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 */ + lcdmem = (uint8_t*)segments_lcdmem[segment]; + + /* Get bitmask for character from table */ + bitmask = segments_bitmask[segment]; + + /* Get bits from font set */ + if ((chr >= 0x30) && (chr <= 0x5A)) { + /* Use font set */ + bits = lcd_font[chr-0x30]; + } + else if (chr == 0x2D) { + /* '-' not in font set */ + bits = BIT1; + } + else { + /* Other characters map to ' ' (blank) */ + bits = 0; + } + + /* 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) { + bits1 = ((bits << 4) & 0xF0) | ((bits >> 4) & 0x0F); + bits = bits1; + + /* When addressing LCD_SEG_L2_5, need to convert ASCII '1' and 'L' to 1 bit, */ + /* because LCD COM/SEG assignment is special for this incomplete character */ + if (segment == LCD_SEG_L2_5) { + if ((chr == '1') || (chr == 'L')) bits = BIT7; + } + } + + /* Physically write to LCD memory */ + write_lcd_mem(lcdmem, bits, bitmask, mode); + } +} + +void display_chars(uint8_t segments, char *str, uint8_t mode) { + uint8_t i; + uint8_t length = 0; /* Write length */ + uint8_t char_start = 0; /* Starting point for consecutive write */ + + switch (segments) { + /* LINE1 */ + case LCD_SEG_L1_3_0: + length=4; + char_start=LCD_SEG_L1_3; + break; + case LCD_SEG_L1_2_0: + length=3; + char_start=LCD_SEG_L1_2; + break; + case LCD_SEG_L1_1_0: + length=2; + char_start=LCD_SEG_L1_1; + break; + case LCD_SEG_L1_3_1: + length=3; + char_start=LCD_SEG_L1_3; + break; + case LCD_SEG_L1_3_2: + length=2; + char_start=LCD_SEG_L1_3; + break; + + /* LINE2 */ + case LCD_SEG_L2_5_0: + length=6; + char_start=LCD_SEG_L2_5; + break; + case LCD_SEG_L2_4_0: + length=5; + char_start=LCD_SEG_L2_4; + break; + case LCD_SEG_L2_3_0: + length=4; + char_start=LCD_SEG_L2_3; + break; + case LCD_SEG_L2_2_0: + length=3; + char_start=LCD_SEG_L2_2; + break; + case LCD_SEG_L2_1_0: + length=2; + char_start=LCD_SEG_L2_1; + break; + case LCD_SEG_L2_5_4: + length=2; + char_start=LCD_SEG_L2_5; + break; + case LCD_SEG_L2_5_2: + length=4; + char_start=LCD_SEG_L2_5; + break; + case LCD_SEG_L2_3_2: + length=2; + char_start=LCD_SEG_L2_3; + break; + case LCD_SEG_L2_4_2: + length=3; + char_start=LCD_SEG_L2_4; + break; + } + + /* Write to consecutive digits */ + for(i=0; i +#include + +/* ************************************************************************************************* */ +/* Global Variable section */ + +/* Table with memory bit assignment for digits "0" to "9" and characters "A" to "Z" */ +/* A */ +/* F B */ +/* G */ +/* E C */ +/* D */ +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 */ +}; + +/* Table with memory address for each display element */ +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, +}; + +/* Table with bit mask for each display element */ +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, +}; + +/* Quick integer to array conversion table for most common integer values + * discarding this would save aprox. 600 bytes codespace but increase cpu time + * for displaying values */ +const uint8_t itoa_conversion_table[][3] = { + "000", "001", "002", "003", "004", "005", "006", "007", "008", "009", "010", "011", "012", "013", "014", "015", + "016", "017", "018", "019", "020", "021", "022", "023", "024", "025", "026", "027", "028", "029", "030", "031", + "032", "033", "034", "035", "036", "037", "038", "039", "040", "041", "042", "043", "044", "045", "046", "047", + "048", "049", "050", "051", "052", "053", "054", "055", "056", "057", "058", "059", "060", "061", "062", "063", + "064", "065", "066", "067", "068", "069", "070", "071", "072", "073", "074", "075", "076", "077", "078", "079", + "080", "081", "082", "083", "084", "085", "086", "087", "088", "089", "090", "091", "092", "093", "094", "095", + "096", "097", "098", "099", "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", "110", "111", + "112", "113", "114", "115", "116", "117", "118", "119", "120", "121", "122", "123", "124", "125", "126", "127", + "128", "129", "130", "131", "132", "133", "134", "135", "136", "137", "138", "139", "140", "141", "142", "143", + "144", "145", "146", "147", "148", "149", "150", "151", "152", "153", "154", "155", "156", "157", "158", "159", + "160", "161", "162", "163", "164", "165", "166", "167", "168", "169", "170", "171", "172", "173", "174", "175", + "176", "177", "178", "179", "180", +}; diff --git a/board/chronos/drivers/display_putchar.c b/board/chronos/drivers/display_putchar.c new file mode 100644 index 000000000..2f1d9468a --- /dev/null +++ b/board/chronos/drivers/display_putchar.c @@ -0,0 +1,42 @@ +#include +#include +#include + +extern int toupper(int c); +extern void (*_putchar)(int c); + +static char display_buf[11]; + +void putchar_to_display(); + +void init_display_putchar() { + memset(display_buf, '\0', 11); + _putchar = putchar_to_display; +} + +void putchar_to_display(int c) { + if (c == '\n') { + display_buf[4] = 1; + return; + } + + if (display_buf[4]) { + memset(display_buf, '\0', 11); + } else { + display_buf[0] = display_buf[1]; + display_buf[1] = display_buf[2]; + display_buf[2] = display_buf[3]; + display_buf[3] = display_buf[5]; + display_buf[5] = display_buf[6]; + display_buf[6] = display_buf[7]; + display_buf[7] = display_buf[8]; + display_buf[8] = display_buf[9]; + } + + display_buf[9] = toupper(c); + + clear_display_all(); + + display_chars(LCD_SEG_L1_3_0, display_buf, SEG_ON); + display_chars(LCD_SEG_L2_5_0, display_buf+4, SEG_ON); +} diff --git a/board/chronos/drivers/include/battery.h b/board/chronos/drivers/include/battery.h new file mode 100644 index 000000000..c6381b721 --- /dev/null +++ b/board/chronos/drivers/include/battery.h @@ -0,0 +1,6 @@ +#ifndef BATTERY_H +#define BATTERY_H + +uint32_t battery_get_voltage(void); + +#endif /* BATTERY_H */ diff --git a/board/chronos/drivers/include/buzzer.h b/board/chronos/drivers/include/buzzer.h new file mode 100644 index 000000000..1786b0c51 --- /dev/null +++ b/board/chronos/drivers/include/buzzer.h @@ -0,0 +1,6 @@ +#ifndef BUZZER_H +#define BUZZER_H + +void buzzer_beep(uint8_t pitch, uint16_t duration); + +#endif /* BUZZER_H */ diff --git a/board/chronos/drivers/include/display.h b/board/chronos/drivers/include/display.h new file mode 100644 index 000000000..3b7c2e131 --- /dev/null +++ b/board/chronos/drivers/include/display.h @@ -0,0 +1,458 @@ +/* ************************************************************************************************* + * + * 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. + * + * ************************************************************************************************* + * Basic display functions. + * ************************************************************************************************/ + +#ifndef __DISPLAY_H +#define __DISPLAY_H + +#define CLOCK_24HR (0) +#define CLOCK_AM_PM (1) +#define CLOCK_DISPLAY_SELECT (2) + + +/* ************************************************************************************************* + * Global Variable section */ + +/* Set of display flags */ +typedef union { + struct { + /* Line1 + Line2 + Icons*/ + uint16_t full_update : 1; // 1 = Redraw all content + uint16_t partial_update : 1; // 1 = Update changes + + // Line only + uint16_t line1_full_update : 1; // 1 = Redraw Line1 content + uint16_t line2_full_update : 1; // 1 = Redraw Line2 content + + // Logic module data update flags + uint16_t update_time : 1; // 1 = Time was updated + uint16_t update_stopwatch : 1; // 1 = Stopwatch was updated + uint16_t update_temperature : 1; // 1 = Temperature was updated + uint16_t update_battery_voltage : 1; // 1 = Battery voltage was updated + uint16_t update_date : 1; // 1 = Date was updated + uint16_t update_alarm : 1; // 1 = Alarm time was updated + uint16_t update_acceleration : 1; // 1 = Acceleration data was updated + } flag; + uint16_t all_flags; // Shortcut to all display flags (for reset) +} s_display_flags_t; + +extern volatile s_display_flags_t display; + +// Constants defined in library +extern const uint8_t lcd_font[]; +extern const uint8_t *segments_lcdmem[]; +extern const uint8_t segments_bitmask[]; +extern const uint8_t itoa_conversion_table[][3]; + +// ************************************************************************************************* +// Defines section + +// Display function modes +#define DISPLAY_LINE_UPDATE_FULL (BIT0) +#define DISPLAY_LINE_UPDATE_PARTIAL (BIT1) +#define DISPLAY_LINE_CLEAR (BIT2) + +// Definitions for line view style +#define DISPLAY_DEFAULT_VIEW (0u) +#define DISPLAY_ALTERNATIVE_VIEW (1u) +#define DISPLAY_ALTERNATIVE2_VIEW (2u) + +// Definitions for line access +#define LINE1 (1u) +#define LINE2 (2u) + +// LCD display modes +#define SEG_OFF (0u) +#define SEG_ON (1u) +#define SEG_ON_BLINK_ON (2u) +#define SEG_ON_BLINK_OFF (3u) +#define SEG_OFF_BLINK_OFF (4u) + +// 7-segment character bit assignments +#define SEG_A (BIT4) +#define SEG_B (BIT5) +#define SEG_C (BIT6) +#define SEG_D (BIT7) +#define SEG_E (BIT2) +#define SEG_F (BIT0) +#define SEG_G (BIT1) + +/* ------------------------------------------ + * LCD symbols for easier access + * + * xxx_SEG_xxx = Seven-segment character (sequence 5-4-3-2-1-0) + * xxx_SYMB_xxx = Display symbol, e.g. "AM" for ante meridiem + * xxx_UNIT_xxx = Display unit, e.g. "km/h" for kilometers per hour + * xxx_ICON_xxx = Display icon, e.g. heart to indicate reception of heart rate data + * xxx_L1_xxx = Item is part of Line1 information + * xxx_L2_xxx = Item is part of Line2 information + */ + +//* Symbols for Line1 */ +#define LCD_SYMB_AM 0 +#define LCD_SYMB_PM 1 +#define LCD_SYMB_ARROW_UP 2 +#define LCD_SYMB_ARROW_DOWN 3 +#define LCD_SYMB_PERCENT 4 + +/* Symbols for Line2 */ +#define LCD_SYMB_TOTAL 5 +#define LCD_SYMB_AVERAGE 6 +#define LCD_SYMB_MAX 7 +#define LCD_SYMB_BATTERY 8 + +/* Units for Line1 */ +#define LCD_UNIT_L1_FT 9 +#define LCD_UNIT_L1_K 10 +#define LCD_UNIT_L1_M 11 +#define LCD_UNIT_L1_I 12 +#define LCD_UNIT_L1_PER_S 13 +#define LCD_UNIT_L1_PER_H 14 +#define LCD_UNIT_L1_DEGREE 15 + +/* Units for Line2 */ +#define LCD_UNIT_L2_KCAL 16 +#define LCD_UNIT_L2_KM 17 +#define LCD_UNIT_L2_MI 18 + +/* Icons */ +#define LCD_ICON_HEART 19 +#define LCD_ICON_STOPWATCH 20 +#define LCD_ICON_RECORD 21 +#define LCD_ICON_ALARM 22 +#define LCD_ICON_BEEPER1 23 +#define LCD_ICON_BEEPER2 24 +#define LCD_ICON_BEEPER3 25 + +/* Line1 7-segments */ +#define LCD_SEG_L1_3 26 +#define LCD_SEG_L1_2 27 +#define LCD_SEG_L1_1 28 +#define LCD_SEG_L1_0 29 +#define LCD_SEG_L1_COL 30 +#define LCD_SEG_L1_DP1 31 +#define LCD_SEG_L1_DP0 32 + +/* Line2 7-segments */ +#define LCD_SEG_L2_5 33 +#define LCD_SEG_L2_4 34 +#define LCD_SEG_L2_3 35 +#define LCD_SEG_L2_2 36 +#define LCD_SEG_L2_1 37 +#define LCD_SEG_L2_0 38 +#define LCD_SEG_L2_COL1 39 +#define LCD_SEG_L2_COL0 40 +#define LCD_SEG_L2_DP 41 + +/* Line1 7-segment arrays */ +#define LCD_SEG_L1_3_0 70 +#define LCD_SEG_L1_2_0 71 +#define LCD_SEG_L1_1_0 72 +#define LCD_SEG_L1_3_1 73 +#define LCD_SEG_L1_3_2 74 + +/* Line2 7-segment arrays */ +#define LCD_SEG_L2_5_0 90 +#define LCD_SEG_L2_4_0 91 +#define LCD_SEG_L2_3_0 92 +#define LCD_SEG_L2_2_0 93 +#define LCD_SEG_L2_1_0 94 +#define LCD_SEG_L2_5_2 95 +#define LCD_SEG_L2_3_2 96 +#define LCD_SEG_L2_5_4 97 +#define LCD_SEG_L2_4_2 98 + +/* LCD controller memory map */ +#define LCD_MEM_1 ((uint8_t*)0x0A20) +#define LCD_MEM_2 ((uint8_t*)0x0A21) +#define LCD_MEM_3 ((uint8_t*)0x0A22) +#define LCD_MEM_4 ((uint8_t*)0x0A23) +#define LCD_MEM_5 ((uint8_t*)0x0A24) +#define LCD_MEM_6 ((uint8_t*)0x0A25) +#define LCD_MEM_7 ((uint8_t*)0x0A26) +#define LCD_MEM_8 ((uint8_t*)0x0A27) +#define LCD_MEM_9 ((uint8_t*)0x0A28) +#define LCD_MEM_10 ((uint8_t*)0x0A29) +#define LCD_MEM_11 ((uint8_t*)0x0A2A) +#define LCD_MEM_12 ((uint8_t*)0x0A2B) + +/* Memory assignment */ +#define LCD_SEG_L1_0_MEM (LCD_MEM_6) +#define LCD_SEG_L1_1_MEM (LCD_MEM_4) +#define LCD_SEG_L1_2_MEM (LCD_MEM_3) +#define LCD_SEG_L1_3_MEM (LCD_MEM_2) +#define LCD_SEG_L1_COL_MEM (LCD_MEM_1) +#define LCD_SEG_L1_DP1_MEM (LCD_MEM_1) +#define LCD_SEG_L1_DP0_MEM (LCD_MEM_5) +#define LCD_SEG_L2_0_MEM (LCD_MEM_8) +#define LCD_SEG_L2_1_MEM (LCD_MEM_9) +#define LCD_SEG_L2_2_MEM (LCD_MEM_10) +#define LCD_SEG_L2_3_MEM (LCD_MEM_11) +#define LCD_SEG_L2_4_MEM (LCD_MEM_12) +#define LCD_SEG_L2_5_MEM (LCD_MEM_12) +#define LCD_SEG_L2_COL1_MEM (LCD_MEM_1) +#define LCD_SEG_L2_COL0_MEM (LCD_MEM_5) +#define LCD_SEG_L2_DP_MEM (LCD_MEM_9) +#define LCD_SYMB_AM_MEM (LCD_MEM_1) +#define LCD_SYMB_PM_MEM (LCD_MEM_1) +#define LCD_SYMB_ARROW_UP_MEM (LCD_MEM_1) +#define LCD_SYMB_ARROW_DOWN_MEM (LCD_MEM_1) +#define LCD_SYMB_PERCENT_MEM (LCD_MEM_5) +#define LCD_SYMB_TOTAL_MEM (LCD_MEM_11) +#define LCD_SYMB_AVERAGE_MEM (LCD_MEM_10) +#define LCD_SYMB_MAX_MEM (LCD_MEM_8) +#define LCD_SYMB_BATTERY_MEM (LCD_MEM_7) +#define LCD_UNIT_L1_FT_MEM (LCD_MEM_5) +#define LCD_UNIT_L1_K_MEM (LCD_MEM_5) +#define LCD_UNIT_L1_M_MEM (LCD_MEM_7) +#define LCD_UNIT_L1_I_MEM (LCD_MEM_7) +#define LCD_UNIT_L1_PER_S_MEM (LCD_MEM_5) +#define LCD_UNIT_L1_PER_H_MEM (LCD_MEM_7) +#define LCD_UNIT_L1_DEGREE_MEM (LCD_MEM_5) +#define LCD_UNIT_L2_KCAL_MEM (LCD_MEM_7) +#define LCD_UNIT_L2_KM_MEM (LCD_MEM_7) +#define LCD_UNIT_L2_MI_MEM (LCD_MEM_7) +#define LCD_ICON_HEART_MEM (LCD_MEM_2) +#define LCD_ICON_STOPWATCH_MEM (LCD_MEM_3) +#define LCD_ICON_RECORD_MEM (LCD_MEM_1) +#define LCD_ICON_ALARM_MEM (LCD_MEM_4) +#define LCD_ICON_BEEPER1_MEM (LCD_MEM_5) +#define LCD_ICON_BEEPER2_MEM (LCD_MEM_6) +#define LCD_ICON_BEEPER3_MEM (LCD_MEM_7) + +/* Bit masks for write access */ +#define LCD_SEG_L1_0_MASK (BIT2+BIT1+BIT0+BIT7+BIT6+BIT5+BIT4) +#define LCD_SEG_L1_1_MASK (BIT2+BIT1+BIT0+BIT7+BIT6+BIT5+BIT4) +#define LCD_SEG_L1_2_MASK (BIT2+BIT1+BIT0+BIT7+BIT6+BIT5+BIT4) +#define LCD_SEG_L1_3_MASK (BIT2+BIT1+BIT0+BIT7+BIT6+BIT5+BIT4) +#define LCD_SEG_L1_COL_MASK (BIT5) +#define LCD_SEG_L1_DP1_MASK (BIT6) +#define LCD_SEG_L1_DP0_MASK (BIT2) +#define LCD_SEG_L2_0_MASK (BIT3+BIT2+BIT1+BIT0+BIT6+BIT5+BIT4) +#define LCD_SEG_L2_1_MASK (BIT3+BIT2+BIT1+BIT0+BIT6+BIT5+BIT4) +#define LCD_SEG_L2_2_MASK (BIT3+BIT2+BIT1+BIT0+BIT6+BIT5+BIT4) +#define LCD_SEG_L2_3_MASK (BIT3+BIT2+BIT1+BIT0+BIT6+BIT5+BIT4) +#define LCD_SEG_L2_4_MASK (BIT3+BIT2+BIT1+BIT0+BIT6+BIT5+BIT4) +#define LCD_SEG_L2_5_MASK (BIT7) +#define LCD_SEG_L2_COL1_MASK (BIT4) +#define LCD_SEG_L2_COL0_MASK (BIT0) +#define LCD_SEG_L2_DP_MASK (BIT7) +#define LCD_SYMB_AM_MASK (BIT1+BIT0) +#define LCD_SYMB_PM_MASK (BIT0) +#define LCD_SYMB_ARROW_UP_MASK (BIT2) +#define LCD_SYMB_ARROW_DOWN_MASK (BIT3) +#define LCD_SYMB_PERCENT_MASK (BIT4) +#define LCD_SYMB_TOTAL_MASK (BIT7) +#define LCD_SYMB_AVERAGE_MASK (BIT7) +#define LCD_SYMB_MAX_MASK (BIT7) +#define LCD_SYMB_BATTERY_MASK (BIT7) +#define LCD_UNIT_L1_FT_MASK (BIT5) +#define LCD_UNIT_L1_K_MASK (BIT6) +#define LCD_UNIT_L1_M_MASK (BIT1) +#define LCD_UNIT_L1_I_MASK (BIT0) +#define LCD_UNIT_L1_PER_S_MASK (BIT7) +#define LCD_UNIT_L1_PER_H_MASK (BIT2) +#define LCD_UNIT_L1_DEGREE_MASK (BIT1) +#define LCD_UNIT_L2_KCAL_MASK (BIT4) +#define LCD_UNIT_L2_KM_MASK (BIT5) +#define LCD_UNIT_L2_MI_MASK (BIT6) +#define LCD_ICON_HEART_MASK (BIT3) +#define LCD_ICON_STOPWATCH_MASK (BIT3) +#define LCD_ICON_RECORD_MASK (BIT7) +#define LCD_ICON_ALARM_MASK (BIT3) +#define LCD_ICON_BEEPER1_MASK (BIT3) +#define LCD_ICON_BEEPER2_MASK (BIT3) +#define LCD_ICON_BEEPER3_MASK (BIT3) + + +/* ************************************************************************************************* + * API section + */ + +/* Physical LCD memory write */ +/* ************************************************************************************************* + * @fn write_segment + * @brief Write to one or multiple LCD segments + * @param lcdmem Pointer to LCD byte memory + * bits Segments to address + * bitmask Bitmask for particular display item + * mode On, off or blink segments + * @return + * ************************************************************************************************/ +void write_lcd_mem(uint8_t *lcdmem, uint8_t bits, uint8_t bitmask, uint8_t state); + +/* Display init / clear */ +/* ************************************************************************************************* + * @fn lcd_init + * @brief Erase LCD memory. Init LCD peripheral. + * @param none + * @return none + * ************************************************************************************************/ +void lcd_init(void); + +/* ************************************************************************************************* + * @fn clear_display + * @brief Erase LINE1 and LINE2 segments. Keep icons. + * @param none + * @return none + * ************************************************************************************************/ +void clear_display(void); + +/* ************************************************************************************************* + * @fn clear_display_all + * @brief Erase LINE1 and LINE2 segments. Clear also function-specific content. + * @param none + * @return none + * ************************************************************************************************/ +void clear_display_all(void); + +/* ************************************************************************************************* + * @fn clear_line + * @brief Erase segments of a given line. + * @param uint8_t line LINE1, LINE2 + * @return none + * ************************************************************************************************/ +void clear_line(uint8_t line); + +/* Blinking function */ +/* ************************************************************************************************* + * @fn start_blink + * @brief Start blinking. + * @param none + * @return none + * ************************************************************************************************/ +void start_blink(void); + +/* ************************************************************************************************* + * @fn stop_blink + * @brief Stop blinking. + * @param none + * @return none + * ************************************************************************************************/ +void stop_blink(void); + +/* ************************************************************************************************* + * @fn stop_blink + * @brief Clear blinking memory. + * @param none + * @return none + * ************************************************************************************************/ +void clear_blink_mem(void); + +/* ************************************************************************************************* + * @fn set_blink_rate + * @brief Set blink rate register bits. + * @param none + * @return none + * ************************************************************************************************/ +void set_blink_rate(uint8_t bits); + +/* Character / symbol draw functions */ +/* ************************************************************************************************* + * @fn display_char + * @brief Write to 7-segment characters. + * @param uint8_t segment A valid LCD segment + * uint8_t chr Character to display + * uint8_t mode SEG_ON, SEG_OFF, SEG_BLINK + * @return none + * ************************************************************************************************/ +void display_char(uint8_t segment, char chr, uint8_t mode); + +/* ************************************************************************************************* + * @FN display_chars + * @brief Write to consecutive 7-segment characters. + * @param uint8_t segments LCD segment array + * uint8_t * str Pointer to a string + * uint8_t mode SEG_ON, SEG_OFF, SEG_BLINK + * @return none + * ************************************************************************************************/ +void display_chars(uint8_t segments, char *str, uint8_t mode); + +/* ************************************************************************************************* + * @fn display_symbol + * @brief Switch symbol on or off on LCD. + * @param uint8_t symbol A valid LCD symbol (index 0..42) + * uint8_t state SEG_ON, SEG_OFF, SEG_BLINK + * @return none + * ************************************************************************************************/ +void display_symbol(uint8_t symbol, uint8_t mode); + +/* Set_value display functions */ +/* ************************************************************************************************* + * @fn display_value1 + * @brief Generic decimal display routine. Used exclusively by set_value function. + * @param uint8_t segments LCD segments where value is displayed + * uint32_t value Integer value to be displayed + * uint8_t digits Number of digits to convert + * uint8_t blanks Number of leadings blanks in itoa result string + * @return none + * ************************************************************************************************/ +void display_value1(uint8_t segments, uint32_t value, uint8_t digits, uint8_t blanks, uint8_t disp_mode); + +/* Integer to string conversion */ +/* ************************************************************************************************* + * @fn itoa + * @brief Generic integer to array routine. Converts integer n to string. + * Default conversion result has leading zeros, e.g. "00123" + * Option to convert leading '0' into whitespace (blanks) + * @param uint32_t n integer to convert + * uint8_t digits number of digits + * uint8_t blanks fill up result string with number of whitespaces instead of leading zeros + * @return uint8_t string + * ************************************************************************************************/ +char *itoa(uint32_t n, uint8_t digits, uint8_t blanks); + +/* Segment index helper function */ +/* ************************************************************************************************* + * @fn switch_seg + * @brief Returns index of 7-segment character. Required for display routines that can draw + * information on both lines. + * @param uint8_t line LINE1, LINE2 + * uint8_t index1 Index of LINE1 + * uint8_t index2 Index of LINE2 + * @return uint8 + * ************************************************************************************************/ +uint8_t switch_seg(uint8_t line, uint8_t index1, uint8_t index2); + +/* ************************************************************************************************* + * @fn display_all_off + * @brief Sets everything of on the display + * @param none + * @return none + * ************************************************************************************************/ +void display_all_off(void); + +#endif /* __DISPLAY_ */ diff --git a/board/chronos/drivers/include/display_putchar.h b/board/chronos/drivers/include/display_putchar.h new file mode 100644 index 000000000..6adbb9c9c --- /dev/null +++ b/board/chronos/drivers/include/display_putchar.h @@ -0,0 +1,6 @@ +#ifndef __DISPLAY_PUTCHAR_H +#define __DISPLAY_PUTCHAR_H + +void init_display_putchar(); + +#endif /* __DISPLAY_PUTCHAR_H */ diff --git a/board/eZ430-Chronos/include/board.h b/board/chronos/include/board.h similarity index 100% rename from board/eZ430-Chronos/include/board.h rename to board/chronos/include/board.h diff --git a/board/chronos/include/buttons.h b/board/chronos/include/buttons.h new file mode 100644 index 000000000..4e7ab28dc --- /dev/null +++ b/board/chronos/include/buttons.h @@ -0,0 +1,11 @@ +#ifndef BUTTONS_H +#define BUTTONS_H + +// Button ports +#define BUTTON_STAR_PIN (BIT2) +#define BUTTON_NUM_PIN (BIT1) +#define BUTTON_UP_PIN (BIT4) +#define BUTTON_DOWN_PIN (BIT0) +#define BUTTON_BACKLIGHT_PIN (BIT3) + +#endif diff --git a/board/chronos/putchar.c b/board/chronos/putchar.c new file mode 100644 index 000000000..436d350f5 --- /dev/null +++ b/board/chronos/putchar.c @@ -0,0 +1,11 @@ +static void _dummy(int c) { +} + +void (*_putchar)(int c) = _dummy; + +int putchar(int c) +{ + _putchar(c); + return c; +} + diff --git a/board/eZ430-Chronos/board_init.c b/board/eZ430-Chronos/board_init.c deleted file mode 100644 index aa52e65af..000000000 --- a/board/eZ430-Chronos/board_init.c +++ /dev/null @@ -1,2 +0,0 @@ -void board_init() { -} diff --git a/board/eZ430-Chronos/debug_uart.c b/board/eZ430-Chronos/debug_uart.c deleted file mode 100644 index d80c9c6e8..000000000 --- a/board/eZ430-Chronos/debug_uart.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include "board.h" - -#define UART1_TX TXBUF1 -#define UART1_WAIT_TXDONE() while( (UTCTL1 & TXEPT) == 0 ) { _NOP(); } - - -int putchar(int c) -{ -// UART1_TX = c; -// UART1_WAIT_TXDONE(); -// -// if (c == 10) { -// UART1_TX = 13; -// UART1_WAIT_TXDONE(); -// } - - return c; -} - - diff --git a/board/eZ430-Chronos/drivers/Jamfile b/board/eZ430-Chronos/drivers/Jamfile deleted file mode 100644 index b2fb968fa..000000000 --- a/board/eZ430-Chronos/drivers/Jamfile +++ /dev/null @@ -1,5 +0,0 @@ -SubDir TOP board eZ430-Chronos drivers ; - -UseModule board_common ; - -Module board_common : display.c display1.c ; diff --git a/board/eZ430-Chronos/drivers/display.c b/board/eZ430-Chronos/drivers/display.c deleted file mode 100644 index c0418f544..000000000 --- a/board/eZ430-Chronos/drivers/display.c +++ /dev/null @@ -1,519 +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. -// -// ************************************************************************************************* -// Display functions. -// ************************************************************************************************* - - -// ************************************************************************************************* -// Include section - -// system -#include - -// driver -#include "cc430x613x.h" -#include "display.h" - - -// ************************************************************************************************* -// Prototypes section -void write_lcd_mem(uint8_t * lcdmem, uint8_t bits, uint8_t bitmask, uint8_t state); -void clear_line(uint8_t line); -void display_symbol(uint8_t symbol, uint8_t mode); -void display_char(uint8_t segment, uint8_t chr, uint8_t mode); -void display_chars(uint8_t segments, uint8_t * str, uint8_t mode); - - -// ************************************************************************************************* -// Defines section - - - -// ************************************************************************************************* -// Global Variable section - -// Display flags -volatile s_display_flags display; - -// Global return string for itoa function -uint8_t itoa_str[8]; - - - -// ************************************************************************************************* -// @fn lcd_init -// @brief Erase LCD memory. Init LCD peripheral. -// @param none -// @return none -// ************************************************************************************************* -void lcd_init(void) -{ - // Clear entire display memory - LCDBMEMCTL |= LCDCLRBM + LCDCLRM; - - // LCD_FREQ = ACLK/16/8 = 256Hz - // Frame frequency = 256Hz/4 = 64Hz, LCD mux 4, LCD on - LCDBCTL0 = (LCDDIV0 + LCDDIV1 + LCDDIV2 + LCDDIV3) | (LCDPRE0 + LCDPRE1) | LCD4MUX | LCDON; - - // LCB_BLK_FREQ = ACLK/8/4096 = 1Hz - LCDBBLKCTL = LCDBLKPRE0 | LCDBLKPRE1 | LCDBLKDIV0 | LCDBLKDIV1 | LCDBLKDIV2 | LCDBLKMOD0; - - // I/O to COM outputs - P5SEL |= (BIT5 | BIT6 | BIT7); - P5DIR |= (BIT5 | BIT6 | BIT7); - - // Activate LCD output - LCDBPCTL0 = 0xFFFF; // Select LCD segments S0-S15 - LCDBPCTL1 = 0x00FF; // Select LCD segments S16-S22 - -#ifdef USE_LCD_CHARGE_PUMP - // Charge pump voltage generated internally, internal bias (V2-V4) generation - LCDBVCTL = LCDCPEN | VLCD_2_72; -#endif -} - - -// ************************************************************************************************* -// @fn clear_display_all -// @brief Erase LINE1 and LINE2 segments. Clear also function-specific content. -// @param none -// @return none -// ************************************************************************************************* -void clear_display_all(void) -{ - // Clear generic content - clear_line(LINE1); - clear_line(LINE2); - - -} - - -// ************************************************************************************************* -// @fn clear_display -// @brief Erase LINE1 and LINE2 segments. Keep icons. -// @param none -// @return none -// ************************************************************************************************* -void clear_display(void) -{ - clear_line(LINE1); - clear_line(LINE2); -} - - -// ************************************************************************************************* -// @fn clear_line -// @brief Erase segments of a given line. -// @param uint8_t line LINE1, LINE2 -// @return none -// ************************************************************************************************* -void clear_line(uint8_t line) -{ - display_chars(switch_seg(line, LCD_SEG_L1_3_0, LCD_SEG_L2_5_0), NULL, SEG_OFF); - if (line == LINE1) - { - display_symbol(LCD_SEG_L1_DP1, SEG_OFF); - display_symbol(LCD_SEG_L1_DP0, SEG_OFF); - display_symbol(LCD_SEG_L1_COL, SEG_OFF); - } - else // line == LINE2 - { - display_symbol(LCD_SEG_L2_DP, SEG_OFF); - display_symbol(LCD_SEG_L2_COL1, SEG_OFF); - display_symbol(LCD_SEG_L2_COL0, SEG_OFF); - } -} - - -// ************************************************************************************************* -// @fn write_segment -// @brief Write to one or multiple LCD segments -// @param lcdmem Pointer to LCD byte memory -// bits Segments to address -// bitmask Bitmask for particular display item -// mode On, off or blink segments -// @return -// ************************************************************************************************* -void write_lcd_mem(uint8_t * lcdmem, uint8_t bits, uint8_t bitmask, uint8_t state) -{ - if (state == SEG_ON) - { - // Clear segments before writing - *lcdmem = (uint8_t)(*lcdmem & ~bitmask); - - // Set visible segments - *lcdmem = (uint8_t)(*lcdmem | bits); - } - else if (state == SEG_OFF) - { - // Clear segments - *lcdmem = (uint8_t)(*lcdmem & ~bitmask); - } - else if (state == SEG_ON_BLINK_ON) - { - // Clear visible / blink segments before writing - *lcdmem = (uint8_t)(*lcdmem & ~bitmask); - *(lcdmem+0x20) = (uint8_t)(*(lcdmem+0x20) & ~bitmask); - - // Set visible / blink segments - *lcdmem = (uint8_t)(*lcdmem | bits); - *(lcdmem+0x20) = (uint8_t)(*(lcdmem+0x20) | bits); - } - else if (state == SEG_ON_BLINK_OFF) - { - // Clear visible segments before writing - *lcdmem = (uint8_t)(*lcdmem & ~bitmask); - - // Set visible segments - *lcdmem = (uint8_t)(*lcdmem | bits); - - // Clear blink segments - *(lcdmem+0x20) = (uint8_t)(*(lcdmem+0x20) & ~bitmask); - } - else if (state == SEG_OFF_BLINK_OFF) - { - // Clear segments - *lcdmem = (uint8_t)(*lcdmem & ~bitmask); - - // Clear blink segments - *(lcdmem+0x20) = (uint8_t)(*(lcdmem+0x20) & ~bitmask); - } -} - - -// ************************************************************************************************* -// @fn itoa -// @brief Generic integer to array routine. Converts integer n to string. -// Default conversion result has leading zeros, e.g. "00123" -// Option to convert leading '0' into whitespace (blanks) -// @param uint32_t n integer to convert -// uint8_t digits number of digits -// uint8_t blanks fill up result string with number of whitespaces instead of leading zeros -// @return uint8_t string -// ************************************************************************************************* -uint8_t * itoa(uint32_t n, uint8_t digits, uint8_t blanks) -{ - uint8_t i; - uint8_t digits1 = digits; - - // Preset result string - memcpy(itoa_str, "0000000", 7); - - // Return empty string if number of digits is invalid (valid range for digits: 1-7) - if ((digits == 0) || (digits > 7)) return (itoa_str); - - // Numbers 0 .. 180 can be copied from itoa_conversion_table without conversion - if (n <= 180) - { - if (digits >= 3) - { - memcpy(itoa_str+(digits-3), itoa_conversion_table[n], 3); - } - else // digits == 1 || 2 - { - memcpy(itoa_str, itoa_conversion_table[n]+(3-digits), digits); - } - } - else // For n > 180 need to calculate string content - { - // Calculate digits from least to most significant number - do - { - itoa_str[digits-1] = n % 10 + '0'; - n /= 10; - } while (--digits > 0); - } - - // Remove specified number of leading '0', always keep last one - i = 0; - while ((itoa_str[i] == '0') && (i < digits1-1)) - { - if (blanks > 0) - { - // Convert only specified number of leading '0' - itoa_str[i]=' '; - blanks--; - } - i++; - } - - return (itoa_str); -} - - -// ************************************************************************************************* -// @fn display_value1 -// @brief Generic decimal display routine. Used exclusively by set_value function. -// @param uint8_t segments LCD segments where value is displayed -// uint32_t value Integer value to be displayed -// uint8_t digits Number of digits to convert -// uint8_t blanks Number of leadings blanks in itoa result string -// @return none -// ************************************************************************************************* -void display_value1(uint8_t segments, uint32_t value, uint8_t digits, uint8_t blanks, uint8_t disp_mode) -{ - uint8_t * str; - - str = itoa(value, digits, blanks); - - // Display string in blink mode - display_chars(segments, str, disp_mode); -} - - -// ************************************************************************************************* -// @fn display_symbol -// @brief Switch symbol on or off on LCD. -// @param uint8_t symbol A valid LCD symbol (index 0..42) -// uint8_t state SEG_ON, SEG_OFF, SEG_BLINK -// @return none -// ************************************************************************************************* -void display_symbol(uint8_t symbol, uint8_t mode) -{ - uint8_t * lcdmem; - uint8_t bits; - uint8_t bitmask; - - if (symbol <= LCD_SEG_L2_DP) - { - // Get LCD memory address for symbol from table - lcdmem = (uint8_t *)segments_lcdmem[symbol]; - - // Get bits for symbol from table - bits = segments_bitmask[symbol]; - - // Bitmask for symbols equals bits - bitmask = bits; - - // Write LCD memory - write_lcd_mem(lcdmem, bits, bitmask, mode); - } -} - - -// ************************************************************************************************* -// @fn display_char -// @brief Write to 7-segment characters. -// @param uint8_t segment A valid LCD segment -// uint8_t chr Character to display -// uint8_t mode SEG_ON, SEG_OFF, SEG_BLINK -// @return none -// ************************************************************************************************* -void display_char(uint8_t segment, uint8_t chr, uint8_t mode) -{ - uint8_t * lcdmem; // Pointer to LCD memory - uint8_t bitmask; // Bitmask for character - uint8_t bits, bits1; // Bits to write - - // 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 - lcdmem = (uint8_t *)segments_lcdmem[segment]; - - // Get bitmask for character from table - bitmask = segments_bitmask[segment]; - - // Get bits from font set - if ((chr >= 0x30) && (chr <= 0x5A)) - { - // Use font set - bits = lcd_font[chr-0x30]; - } - else if (chr == 0x2D) - { - // '-' not in font set - bits = BIT1; - } - else - { - // Other characters map to ' ' (blank) - bits = 0; - } - - // 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) - { - bits1 = ((bits << 4) & 0xF0) | ((bits >> 4) & 0x0F); - bits = bits1; - - // When addressing LCD_SEG_L2_5, need to convert ASCII '1' and 'L' to 1 bit, - // because LCD COM/SEG assignment is special for this incomplete character - if (segment == LCD_SEG_L2_5) - { - if ((chr == '1') || (chr == 'L')) bits = BIT7; - } - } - - // Physically write to LCD memory - write_lcd_mem(lcdmem, bits, bitmask, mode); - } -} - - -// ************************************************************************************************* -// @fn display_chars -// @brief Write to consecutive 7-segment characters. -// @param uint8_t segments LCD segment array -// uint8_t * str Pointer to a string -// uint8_t mode SEG_ON, SEG_OFF, SEG_BLINK -// @return none -// ************************************************************************************************* -void display_chars(uint8_t segments, uint8_t * str, uint8_t mode) -{ - uint8_t i; - uint8_t length = 0; // Write length - uint8_t char_start = 0; // Starting point for consecutive write - - switch (segments) - { - // LINE1 - case LCD_SEG_L1_3_0: length=4; char_start=LCD_SEG_L1_3; break; - case LCD_SEG_L1_2_0: length=3; char_start=LCD_SEG_L1_2; break; - case LCD_SEG_L1_1_0: length=2; char_start=LCD_SEG_L1_1; break; - case LCD_SEG_L1_3_1: length=3; char_start=LCD_SEG_L1_3; break; - case LCD_SEG_L1_3_2: length=2; char_start=LCD_SEG_L1_3; break; - - // LINE2 - case LCD_SEG_L2_5_0: length=6; char_start=LCD_SEG_L2_5; break; - case LCD_SEG_L2_4_0: length=5; char_start=LCD_SEG_L2_4; break; - case LCD_SEG_L2_3_0: length=4; char_start=LCD_SEG_L2_3; break; - case LCD_SEG_L2_2_0: length=3; char_start=LCD_SEG_L2_2; break; - case LCD_SEG_L2_1_0: length=2; char_start=LCD_SEG_L2_1; break; - case LCD_SEG_L2_5_4: length=2; char_start=LCD_SEG_L2_5; break; - case LCD_SEG_L2_5_2: length=4; char_start=LCD_SEG_L2_5; break; - case LCD_SEG_L2_3_2: length=2; char_start=LCD_SEG_L2_3; break; - case LCD_SEG_L2_4_2: length=3; char_start=LCD_SEG_L2_4; break; - } - - // Write to consecutive digits - for(i=0; i) - 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 -}; - - -// Table with memory address for each display element -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, -}; - - -// Table with bit mask for each display element -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, -}; - - -// Quick integer to array conversion table for most common integer values -const uint8_t itoa_conversion_table[][3] = -{ - "000", "001", "002", "003", "004", "005", "006", "007", "008", "009", "010", "011", "012", "013", "014", "015", - "016", "017", "018", "019", "020", "021", "022", "023", "024", "025", "026", "027", "028", "029", "030", "031", - "032", "033", "034", "035", "036", "037", "038", "039", "040", "041", "042", "043", "044", "045", "046", "047", - "048", "049", "050", "051", "052", "053", "054", "055", "056", "057", "058", "059", "060", "061", "062", "063", - "064", "065", "066", "067", "068", "069", "070", "071", "072", "073", "074", "075", "076", "077", "078", "079", - "080", "081", "082", "083", "084", "085", "086", "087", "088", "089", "090", "091", "092", "093", "094", "095", - "096", "097", "098", "099", "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", "110", "111", - "112", "113", "114", "115", "116", "117", "118", "119", "120", "121", "122", "123", "124", "125", "126", "127", - "128", "129", "130", "131", "132", "133", "134", "135", "136", "137", "138", "139", "140", "141", "142", "143", - "144", "145", "146", "147", "148", "149", "150", "151", "152", "153", "154", "155", "156", "157", "158", "159", - "160", "161", "162", "163", "164", "165", "166", "167", "168", "169", "170", "171", "172", "173", "174", "175", - "176", "177", "178", "179", "180", -}; - diff --git a/board/msb-430-common/Jamfile b/board/msb-430-common/Jamfile new file mode 100644 index 000000000..78807c144 --- /dev/null +++ b/board/msb-430-common/Jamfile @@ -0,0 +1,34 @@ +# ****************************************************************************** +# Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved. +# +# These sources were developed at the Freie Universitaet Berlin, Computer +# Systems and Telematics group (http://cst.mi.fu-berlin.de). +# ------------------------------------------------------------------------------ +# This file is part of FeuerWare. +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# FeuerWare is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see http://www.gnu.org/licenses/ . +# ------------------------------------------------------------------------------ +# For further information and questions please use the web site +# http://scatterweb.mi.fu-berlin.de +# and the mailinglist (subscription via web site) +# scatterweb@lists.spline.inf.fu-berlin.de +# ****************************************************************************** +# $Id$ + +SubDir TOP board msb-430-common ; + +Module board : board_init.c uart1.c ; +Module board_config : board_config.c : flashrom ; +UseModule board ; + +SubInclude TOP cpu $(CPU) ; diff --git a/board/msb-430-common/Jamrules.msb-430-common b/board/msb-430-common/Jamrules.msb-430-common new file mode 100644 index 000000000..7eee8b088 --- /dev/null +++ b/board/msb-430-common/Jamrules.msb-430-common @@ -0,0 +1,38 @@ +# ****************************************************************************** +# Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved. +# +# These sources were developed at the Freie Universitaet Berlin, Computer +# Systems and Telematics group (http://cst.mi.fu-berlin.de). +# ------------------------------------------------------------------------------ +# This file is part of FeuerWare. +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# FeuerWare is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see http://www.gnu.org/licenses/ . +# ------------------------------------------------------------------------------ +# For further information and questions please use the web site +# http://scatterweb.mi.fu-berlin.de +# and the mailinglist (subscription via web site) +# scatterweb@lists.spline.inf.fu-berlin.de +# ****************************************************************************** +# $Id$ + +CPU = msp430x16x ; +MCU = msp430x1612 ; + +FLASH_PORT ?= "$(PORT)" ; +FLASHER ?= mspdebug ; +FLASHFLAGS ?= -d $(FLASH_PORT) -j uif ; + +RESET ?= $(FLASHER) $(FLASHFLAGS) reset ; + +HDRS += [ FPath $(TOP) board msb-430-common include ] ; +HDRS += [ FPath $(TOP) board msb-430-common drivers include ] ; diff --git a/board/msb-430-common/board_config.c b/board/msb-430-common/board_config.c new file mode 100644 index 000000000..f22e513b2 --- /dev/null +++ b/board/msb-430-common/board_config.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include + +void config_load(void) { + if (*((uint16_t*) INFOMEM) == CONFIG_KEY) { + memcpy(&sysconfig, (char*) (INFOMEM + sizeof(CONFIG_KEY)), sizeof(sysconfig)); + } + else { + config_save(); + } +} + +uint8_t config_save(void) { + configmem_t mem = { CONFIG_KEY, sysconfig }; + return (flashrom_erase((uint8_t*) INFOMEM) && flashrom_write((uint8_t*) INFOMEM, (char*) &mem, sizeof(mem))); +} diff --git a/board/msb-430h/board_init.c b/board/msb-430-common/board_init.c similarity index 99% rename from board/msb-430h/board_init.c rename to board/msb-430-common/board_init.c index 7dee70e3b..467360044 100644 --- a/board/msb-430h/board_init.c +++ b/board/msb-430-common/board_init.c @@ -201,7 +201,7 @@ void board_init() { msp430_cpu_init(); msb_ports_init(); - RED_ON; + LED_RED_ON; msp430_set_cpu_speed(7372800uL); } diff --git a/board/msb-430-common/drivers/include/sht11-board.h b/board/msb-430-common/drivers/include/sht11-board.h new file mode 100644 index 000000000..a4debd447 --- /dev/null +++ b/board/msb-430-common/drivers/include/sht11-board.h @@ -0,0 +1,61 @@ +/****************************************************************************** +Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved. + +These sources were developed at the Freie Universitaet Berlin, Computer Systems +and Telematics group (http://cst.mi.fu-berlin.de). +------------------------------------------------------------------------------- +This file is part of FeuerWare. + +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +FeuerWare is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see http://www.gnu.org/licenses/ . +-------------------------------------------------------------------------------- +For further information and questions please use the web site + http://scatterweb.mi.fu-berlin.de +and the mailinglist (subscription via web site) + scatterweb@lists.spline.inf.fu-berlin.de +*******************************************************************************/ + +#ifndef SHT11BOARD_H_ +#define SHT11BOARD_H_ + +/** + * @ingroup msb_430h + * @{ + */ + +/** + * @file + * @brief SHT11 Device Driver Configuration For MSB-430 Platform + * + * @author Freie Universität Berlin, Computer Systems & Telematics, µkleos + * @version $Revision$ + * + * @note $Id$ + */ +#include +#include + +/* SCK = P3B5 + * DATA = P3B4 + */ + +#define SHT11_SCK_LOW P3OUT &= ~(BIT5); /**< serial clock line low */ +#define SHT11_SCK_HIGH P3OUT |= BIT5; /**< serial clock line high */ +#define SHT11_DATA (P3IN & BIT5) /**< read serial I/O */ +#define SHT11_DATA_LOW P3OUT &= ~(BIT5); /**< serial I/O line low */ +#define SHT11_DATA_HIGH P3OUT |= BIT5; /**< serial I/O line high */ +#define SHT11_DATA_IN P3DIR &= ~(BIT5); /**< serial I/O as input */ +#define SHT11_DATA_OUT P3DIR |= BIT5; /**< serial I/O as output */ +#define SHT11_INIT P3DIR |= BIT5; /* FIO1DIR |= BIT25; PINSEL3 &= ~(BIT14|BIT15 | BIT16|BIT17); */ + +/** @} */ +#endif /* SHT11BOARD_H_ */ diff --git a/board/msb-430-common/include/board-conf.h b/board/msb-430-common/include/board-conf.h new file mode 100644 index 000000000..e85c3128f --- /dev/null +++ b/board/msb-430-common/include/board-conf.h @@ -0,0 +1,6 @@ +#ifndef BOARD_CONF_H +#define BOARD_CONF_H + +#define INFOMEM (0x1000) + +#endif /* BOARD-CONF_H */ diff --git a/board/msb-430-common/putchar.c b/board/msb-430-common/putchar.c new file mode 100644 index 000000000..4193c0db4 --- /dev/null +++ b/board/msb-430-common/putchar.c @@ -0,0 +1,7 @@ +#include + +void (_putchar(int)) = uart1_putchar; + +void putchar(int c) { + _putchar(c); +} diff --git a/board/msb-430h/debug_uart.c b/board/msb-430-common/uart1.c similarity index 100% rename from board/msb-430h/debug_uart.c rename to board/msb-430-common/uart1.c diff --git a/board/msb-430/Jamfile b/board/msb-430/Jamfile new file mode 100644 index 000000000..f2592c24c --- /dev/null +++ b/board/msb-430/Jamfile @@ -0,0 +1,32 @@ +# ****************************************************************************** +# Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved. +# +# These sources were developed at the Freie Universitaet Berlin, Computer +# Systems and Telematics group (http://cst.mi.fu-berlin.de). +# ------------------------------------------------------------------------------ +# This file is part of FeuerWare. +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# FeuerWare is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see http://www.gnu.org/licenses/ . +# ------------------------------------------------------------------------------ +# For further information and questions please use the web site +# http://scatterweb.mi.fu-berlin.de +# and the mailinglist (subscription via web site) +# scatterweb@lists.spline.inf.fu-berlin.de +# ****************************************************************************** +# $Id$ + +SubDir TOP board msb-430 ; + +SubInclude TOP board msb-430-common ; +SubInclude TOP cpu $(CPU) ; + diff --git a/board/msb-430/Jamrules.msb-430 b/board/msb-430/Jamrules.msb-430 new file mode 100644 index 000000000..ae1d28b44 --- /dev/null +++ b/board/msb-430/Jamrules.msb-430 @@ -0,0 +1,3 @@ +BOARD = msb-430 ; + +include $(TOP)/board/msb-430-common/Jamrules.msb-430-common ; diff --git a/board/msb-430/include/board.h b/board/msb-430/include/board.h new file mode 100644 index 000000000..18d4a0472 --- /dev/null +++ b/board/msb-430/include/board.h @@ -0,0 +1,70 @@ +/****************************************************************************** +Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved. + +These sources were developed at the Freie Universitaet Berlin, Computer Systems +and Telematics group (http://cst.mi.fu-berlin.de). +------------------------------------------------------------------------------- +This file is part of FeuerWare. + +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +FeuerWare is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see http://www.gnu.org/licenses/ . +-------------------------------------------------------------------------------- +For further information and questions please use the web site + http://scatterweb.mi.fu-berlin.de +and the mailinglist (subscription via web site) + scatterweb@lists.spline.inf.fu-berlin.de +*******************************************************************************/ + +#ifndef _MSB_BOARD_H +#define _MSB_BOARD_H + +/** + * @defgroup msb_430h ScatterWeb MSB-430H + * @ingroup msp430 + * +

Compontents

+\li MSP430 +\li CC1100 + +* @{ +*/ + +/** + * @file + * @brief MSB-430H Board + * + * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project + * @version $Revision$ + * + * @note $Id$ + */ + +//MSB430 core +#define MSP430_INITIAL_CPU_SPEED 7372800uL +#define MSP430_HAS_DCOR 1 +#define MSP430_HAS_EXTERNAL_CRYSTAL 0 + +/* LEDs ports MSB430 */ +#define LEDS_PxDIR P5DIR +#define LEDS_PxOUT P5OUT +#define LEDS_CONF_RED 0x80 +#define LEDS_CONF_GREEN 0x00 +#define LEDS_CONF_YELLOW 0x00 + +#define LED_RED_ON LEDS_PxOUT &=~LEDS_CONF_RED +#define LED_RED_OFF LEDS_PxOUT |= LEDS_CONF_RED +#define LED_RED_TOGGLE LEDS_PxOUT ^= LEDS_CONF_RED + +#include + +/** @} */ +#endif // _MSB_BOARD_H diff --git a/board/msb-430h/Jamfile b/board/msb-430h/Jamfile index b1181a57d..9f9ee47bf 100644 --- a/board/msb-430h/Jamfile +++ b/board/msb-430h/Jamfile @@ -27,9 +27,7 @@ SubDir TOP board msb-430h ; -Module board : board_init.c debug_uart.c ; -UseModule board ; - -Module board_cc1100 : driver_cc1100.c ; +Module board_cc110x : driver_cc110x.c : cc110x_spi ; +SubInclude TOP board msb-430-common ; SubInclude TOP cpu $(CPU) ; diff --git a/board/msb-430h/Jamrules.msb-430h b/board/msb-430h/Jamrules.msb-430h index 41bf0779d..d1913ed54 100644 --- a/board/msb-430h/Jamrules.msb-430h +++ b/board/msb-430h/Jamrules.msb-430h @@ -1,37 +1,3 @@ -# ****************************************************************************** -# Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved. -# -# These sources were developed at the Freie Universitaet Berlin, Computer -# Systems and Telematics group (http://cst.mi.fu-berlin.de). -# ------------------------------------------------------------------------------ -# This file is part of FeuerWare. -# -# This program is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, either version 3 of the License, or (at your option) any later -# version. -# -# FeuerWare is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along with -# this program. If not, see http://www.gnu.org/licenses/ . -# ------------------------------------------------------------------------------ -# For further information and questions please use the web site -# http://scatterweb.mi.fu-berlin.de -# and the mailinglist (subscription via web site) -# scatterweb@lists.spline.inf.fu-berlin.de -# ****************************************************************************** -# $Id$ - BOARD = msb-430h ; -CPU = msp430 ; -MCU = msp430x1612 ; - -FLASH_PORT ?= /dev/ttyUSB0 ; -FLASHER ?= mspdebug ; -FLASHFLAGS ?= -d $(FLASH_PORT) -j uif ; - -RESET ?= $(FLASHER) $(FLASHFLAGS) reset ; +include $(TOP)/board/msb-430-common/Jamrules.msb-430-common ; diff --git a/board/msb-430h/driver_cc1100.c b/board/msb-430h/driver_cc110x.c similarity index 84% rename from board/msb-430h/driver_cc1100.c rename to board/msb-430h/driver_cc110x.c index 9575bee6a..9316e8bf5 100644 --- a/board/msb-430h/driver_cc1100.c +++ b/board/msb-430h/driver_cc110x.c @@ -23,8 +23,8 @@ Boston, MA 02111-1307, USA. */ #include #include -#include -#include +#include +#include #define CC1100_GDO0 (P2IN & 0x02) // read serial I/O (GDO0) #define CC1100_GDO1 (P3IN & 0x04) // read serial I/O (GDO1) @@ -39,61 +39,61 @@ Boston, MA 02111-1307, USA. */ volatile int abort_count; volatile int retry_count = 0; -void cc1100_gdo0_enable(void) +void cc110x_gdo0_enable(void) { P2IFG &= ~0x02; /* Clear IFG for GDO0 */ P2IE |= 0x02; /* Enable interrupt for GDO0 */ } -void cc1100_gdo0_disable(void) +void cc110x_gdo0_disable(void) { P2IE &= ~0x02; /* Disable interrupt for GDO0 */ P2IFG &= ~0x02; /* Clear IFG for GDO0 */ } -void cc1100_gdo2_enable(void) +void cc110x_gdo2_enable(void) { P2IFG &= ~0x01; /* Clear IFG for GDO2 */ P2IE |= 0x01; /* Enable interrupt for GDO2 */ } -void cc1100_gdo2_disable(void) +void cc110x_gdo2_disable(void) { P2IE &= ~0x01; /* Disable interrupt for GDO2 */ P2IFG &= ~0x01; /* Clear IFG for GDO2 */ } -void cc1100_before_send(void) +void cc110x_before_send(void) { // Disable GDO2 interrupt before sending packet - cc1100_gdo2_disable(); + cc110x_gdo2_disable(); } -void cc1100_after_send(void) +void cc110x_after_send(void) { // Enable GDO2 interrupt after sending packet - cc1100_gdo2_enable(); + cc110x_gdo2_enable(); } -int cc1100_get_gdo0(void) { +int cc110x_get_gdo0(void) { return CC1100_GDO0; } -int cc1100_get_gdo1(void) { +int cc110x_get_gdo1(void) { return CC1100_GDO1; } -int cc1100_get_gdo2(void) { +int cc110x_get_gdo2(void) { return CC1100_GDO2; } -void cc1100_spi_cs(void) +void cc110x_spi_cs(void) { CC1100_CS_LOW; } -uint8_t cc1100_txrx(uint8_t data) +uint8_t cc110x_txrx(uint8_t data) { /* Ensure TX Buf is empty */ long c = 0; @@ -103,20 +103,20 @@ uint8_t cc1100_txrx(uint8_t data) while(!(IFG1 & UTXIFG0)) { if (c++ == 1000000) - puts("cc1100_txrx alarm()"); + puts("cc110x_txrx alarm()"); } /* Wait for Byte received */ c = 0; while(!(IFG1 & URXIFG0)) { if (c++ == 1000000) - puts("cc1100_txrx alarm()"); + puts("cc110x_txrx alarm()"); } return RXBUF0; } -void cc1100_spi_select(void) +void cc110x_spi_select(void) { // Switch to GDO mode P3SEL &= ~0x04; @@ -147,11 +147,11 @@ void cc1100_spi_select(void) P3SEL |= 0x04; } -void cc1100_spi_unselect(void) { +void cc110x_spi_unselect(void) { CC1100_CS_HIGH; } -void cc1100_init_interrupts(void) +void cc110x_init_interrupts(void) { unsigned int state = disableIRQ(); /* Disable all interrupts */ P2SEL = 0x00; /* must be <> 1 to use interrupts */ @@ -163,7 +163,7 @@ void cc1100_init_interrupts(void) restoreIRQ(state); /* Enable all interrupts */ } -void cc1100_spi_init(uint8_t clockrate) +void cc110x_spi_init(uint8_t clockrate) { // Switch off async UART while(!(UTCTL0 & TXEPT)); // Wait for empty UxTXBUF register @@ -197,8 +197,8 @@ void cc1100_spi_init(uint8_t clockrate) // #include // #include // #include "type.h" -// #include "cc1100_defines.h" -// #include "driver_cc1100.h" +// #include "cc110x_defines.h" +// #include "driver_cc110x.h" // #include "driver_system.h" // #include "spi0.h" // @@ -213,17 +213,17 @@ void cc1100_spi_init(uint8_t clockrate) // // void spiInitTrx(void) // // // // DESCRIPTION: -// // This function puts the cc1100 into spi mode. You have to call this bevore every spi transaction. +// // This function puts the cc110x into spi mode. You have to call this bevore every spi transaction. // // // //------------------------------------------------------------------------------------------------------- // // -// void drivercc1100_spiwriteburstreg(uint8_t addr, unsigned char *buffer, uint8_t count) +// void drivercc110x_spiwriteburstreg(uint8_t addr, unsigned char *buffer, uint8_t count) // { // uint8_t i; // long c; -// drivercc1100_spiinittrx(); -// drivercc1100_trxspi(addr | CC1100_WRITE_BURST); +// drivercc110x_spiinittrx(); +// drivercc110x_trxspi(addr | CC1100_WRITE_BURST); // for (i = 0; i < count; i++) // { // c = 0; @@ -247,11 +247,11 @@ void cc1100_spi_init(uint8_t clockrate) // CC1100_CS_HIGH; // } // -// void drivercc1100_spireadburstreg(uint8_t addr, char *buffer, uint8_t count) +// void drivercc110x_spireadburstreg(uint8_t addr, char *buffer, uint8_t count) // { // uint8_t i; -// drivercc1100_spiinittrx(); -// drivercc1100_trxspi(addr | CC1100_READ_BURST); +// drivercc110x_spiinittrx(); +// drivercc110x_trxspi(addr | CC1100_READ_BURST); // for (i = 0; i < count; i++) // { // long c = 0; @@ -275,21 +275,21 @@ void cc1100_spi_init(uint8_t clockrate) // CC1100_CS_HIGH; // } // -// void drivercc1100_load(callback_t cs_cb,callback_t paket_cb) +// void drivercc110x_load(callback_t cs_cb,callback_t paket_cb) // { // _paket_cb = paket_cb; // _cs_cb = cs_cb; // spi0_init(0); // } // -// void drivercc1100_aftersend(void) +// void drivercc110x_aftersend(void) // { // CLEAR(P2IFG, 0x01); // SET(P2IE, 0x01); /* Enable interrupts on port 2 pin 0 */ // CLEAR(P4OUT, 0x08); /* Turn off Sending Led*/ // } // -// void drivercc1100_initinterrupts(void) +// void drivercc110x_initinterrupts(void) // { // _DINT(); /* Disable all interrupts */ // P2SEL = 0x00; /* must be <> 1 to use interrupts */ @@ -301,7 +301,7 @@ void cc1100_spi_init(uint8_t clockrate) // _EINT(); /* Enable all interrupts */ // } // -// void drivercc1100_beforesend(void) +// void drivercc110x_beforesend(void) // { // /* Turn on Led while sending paket for debug reasons */ // SET(P4OUT, 0x08); @@ -319,25 +319,24 @@ void cc1100_spi_init(uint8_t clockrate) /* * CC1100 receive interrupt */ -interrupt (PORT2_VECTOR) __attribute__ ((naked)) cc1100_isr(void){ +interrupt (PORT2_VECTOR) __attribute__ ((naked)) cc110x_isr(void){ __enter_isr(); -puts("cc1100_isr()"); +puts("cc110x_isr()"); // if (system_state.POWERDOWN) SPI_INIT; /* Initialize SPI after wakeup */ /* Check IFG */ if ((P2IFG & 0x01) != 0) { P2IFG &= ~0x01; - cc1100_gdo2_irq(); + cc110x_gdo2_irq(); } else if ((P2IFG & 0x02) != 0) { - cc1100_gdo0_irq(); + cc110x_gdo0_irq(); P2IE &= ~0x02; // Disable interrupt for GDO0 P2IFG &= ~0x02; // Clear IFG for GDO0 } else { - puts("cc1100_isr(): unexpected IFG!"); + puts("cc110x_isr(): unexpected IFG!"); /* Should not occur - only Port 2 Pin 0 interrupts are enabled */ // CLEAR(P2IFG, 0xFF); /* Clear all flags */ } // if (system_state.POWERDOWN != 0) END_LPM3; __exit_isr(); } - diff --git a/board/msb-430h/include/board.h b/board/msb-430h/include/board.h index ef2bbb658..d9634d6b4 100644 --- a/board/msb-430h/include/board.h +++ b/board/msb-430h/include/board.h @@ -60,8 +60,9 @@ and the mailinglist (subscription via web site) #define LEDS_CONF_GREEN 0x00 #define LEDS_CONF_YELLOW 0x00 -#define RED_ON LEDS_PxOUT &=~LEDS_CONF_RED -#define RED_OFF LEDS_PxOUT |= LEDS_CONF_RED +#define LED_RED_ON LEDS_PxOUT &=~LEDS_CONF_RED +#define LED_RED_OFF LEDS_PxOUT |= LEDS_CONF_RED +#define LED_RED_TOGGLE LEDS_PxOUT ^= LEDS_CONF_RED #include diff --git a/board/msba2-common/Jamfile b/board/msba2-common/Jamfile new file mode 100644 index 000000000..ff9a8ccd4 --- /dev/null +++ b/board/msba2-common/Jamfile @@ -0,0 +1,7 @@ +SubDir TOP board msba2-common ; + +Module board_common : board_common_init.c ; +Module board_config : board_config.c ; + +SubInclude TOP board msba2-common drivers ; + diff --git a/board/msba2/Jamfile.msba2 b/board/msba2-common/Jamfile.msba2 similarity index 90% rename from board/msba2/Jamfile.msba2 rename to board/msba2-common/Jamfile.msba2 index 44014a6c9..e9e291c90 100644 --- a/board/msba2/Jamfile.msba2 +++ b/board/msba2-common/Jamfile.msba2 @@ -25,7 +25,6 @@ # ****************************************************************************** # $Id$ -#LinkLibraries $(BOARD).elf : sys-drivers.a net_mm.a sys-lib.a fat-lib.a -# cpu_drivers.a board_drivers.a cc110x.a hal.a hal_drivers.a lpc2387_hal.a ; +Module msba2_common : board_init.c ; include [ FPath $(TOP) cpu arm_common Jamfile.arm_common ] ; diff --git a/board/msba2-common/Jamrules.msba2 b/board/msba2-common/Jamrules.msba2 new file mode 100644 index 000000000..1bce8075c --- /dev/null +++ b/board/msba2-common/Jamrules.msba2 @@ -0,0 +1,34 @@ +# ****************************************************************************** +# Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved. +# +# These sources were developed at the Freie Universitaet Berlin, Computer +# Systems and Telematics group (http://cst.mi.fu-berlin.de). +# ------------------------------------------------------------------------------ +# This file is part of FeuerWare. +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# FeuerWare is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see http://www.gnu.org/licenses/ . +# ------------------------------------------------------------------------------ +# For further information and questions please use the web site +# http://scatterweb.mi.fu-berlin.de +# and the mailinglist (subscription via web site) +# scatterweb@lists.spline.inf.fu-berlin.de +# ****************************************************************************** +# $Id$ + +CPU = lpc2387 ; + +HDRS += [ FPath $(TOP) board msba2-common include ] ; +HDRS += [ FPath $(TOP) board msba2-common drivers include ] ; + +FLASHER ?= $(POSIXSHELL) lpc2k_pgm ; +FLASHFLAGS ?= "$(PORT)" ; diff --git a/board/msba2-common/board_common_init.c b/board/msba2-common/board_common_init.c new file mode 100644 index 000000000..8d7c35962 --- /dev/null +++ b/board/msba2-common/board_common_init.c @@ -0,0 +1,125 @@ +/****************************************************************************** +Copyright 2008-2009, Freie Universitaet Berlin (FUB). All rights reserved. + +These sources were developed at the Freie Universitaet Berlin, Computer Systems +and Telematics group (http://cst.mi.fu-berlin.de). +------------------------------------------------------------------------------- +This file is part of FeuerWare. + +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +FeuerWare is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see http://www.gnu.org/licenses/ . +-------------------------------------------------------------------------------- +For further information and questions please use the web site + http://scatterweb.mi.fu-berlin.de +and the mailinglist (subscription via web site) + scatterweb@lists.spline.inf.fu-berlin.de +*******************************************************************************/ + +/** + * @ingroup msba2 + * @{ + */ + +/** + * @file + * @brief MSB-A2 board initialization + * + * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project + * @author Heiko Will + * @author Kaspar Schleiser + * @author Michael Baar + * + * @note $Id$ + */ +#include +#include +#include +#include +#include +#include +#include + +#define PCRTC BIT9 +#define CL_CPU_DIV 4 + +/*---------------------------------------------------------------------------*/ +/** + * @brief Enabling MAM and setting number of clocks used for Flash memory fetch + * @internal + */ +static void +init_mam(void) +{ + MAMCR = 0x0000; + MAMTIM = 0x0003; + MAMCR = 0x0002; +} +/*---------------------------------------------------------------------------*/ +static inline void +pllfeed(void) +{ + PLLFEED = 0xAA; + PLLFEED = 0x55; +} +/*---------------------------------------------------------------------------*/ +void init_clks1(void) +{ + // Disconnect PLL + PLLCON &= ~0x0002; + pllfeed(); + + // Disable PLL + PLLCON &= ~0x0001; + pllfeed(); + + SCS |= 0x20; // Enable main OSC + while( !(SCS & 0x40) ); // Wait until main OSC is usable + + /* select main OSC, 16MHz, as the PLL clock source */ + CLKSRCSEL = 0x0001; + + // Setting Multiplier and Divider values + PLLCFG = 0x0008; // M=9 N=1 Fcco = 288 MHz + pllfeed(); + + // Enabling the PLL */ + PLLCON = 0x0001; + pllfeed(); + + /* Set clock divider to 4 (value+1) */ + CCLKCFG = CL_CPU_DIV - 1; // Fcpu = 72 MHz + +#if USE_USB + USBCLKCFG = USBCLKDivValue; /* usbclk = 288 MHz/6 = 48 MHz */ +#endif +} + +void init_clks2(void){ + // Wait for the PLL to lock to set frequency + while(!(PLLSTAT & BIT26)); + + // Connect the PLL as the clock source + PLLCON = 0x0003; + pllfeed(); + + /* Check connect bit status */ + while (!(PLLSTAT & BIT25)); +} + +void bl_init_clks(void) +{ + PCONP = PCRTC; // switch off everything except RTC + init_clks1(); + init_clks2(); + init_mam(); +} + diff --git a/board/msba2-common/board_config.c b/board/msba2-common/board_config.c new file mode 100644 index 000000000..8eff7e9db --- /dev/null +++ b/board/msba2-common/board_config.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include + +void config_load(void) { + extern char configmem[]; + if (*((uint16_t*) configmem) == CONFIG_KEY) { + memcpy(&sysconfig, (configmem + sizeof(CONFIG_KEY)), sizeof(sysconfig)); + } + else { + config_save(); + } +} + +uint8_t config_save(void) { + configmem_t mem = { CONFIG_KEY, sysconfig }; + return (flashrom_erase((uint8_t*) &configmem) && flashrom_write((uint8_t*) &configmem, (char*) &mem, sizeof(mem))); +} diff --git a/board/msba2-common/drivers/Jamfile b/board/msba2-common/drivers/Jamfile new file mode 100644 index 000000000..ed8e73498 --- /dev/null +++ b/board/msba2-common/drivers/Jamfile @@ -0,0 +1,6 @@ +SubDir TOP board msba2-common drivers ; + +Module board_cc110x : msba2-cc110x.c : cc110x_spi gpioint ; +Module board_ltc4150 : msba2-ltc4150.c : gpioint ; +Module board_uart : msba2-uart0.c : chardev_thread ringbuffer ; + diff --git a/board/msba2/drivers/include/sht11-board.h b/board/msba2-common/drivers/include/sht11-board.h similarity index 93% rename from board/msba2/drivers/include/sht11-board.h rename to board/msba2-common/drivers/include/sht11-board.h index fc0313906..c35fb0078 100644 --- a/board/msba2/drivers/include/sht11-board.h +++ b/board/msba2-common/drivers/include/sht11-board.h @@ -54,10 +54,5 @@ and the mailinglist (subscription via web site) #define SHT11_DATA_OUT (FIO1DIR |= BIT26) // serial I/O as output #define SHT11_INIT FIO1DIR |= BIT25; PINSEL3 &= ~(BIT14|BIT15 | BIT16|BIT17); -/* time to wait after toggling the data line */ -#define SHT11_DATA_WAIT (50) -/* time to wait after toggling the clock line */ -#define SHT11_CLK_WAIT (10) - /** @} */ #endif /* SHT11BOARD_H_ */ diff --git a/board/msba2/drivers/include/uart0.h b/board/msba2-common/drivers/include/uart0.h similarity index 100% rename from board/msba2/drivers/include/uart0.h rename to board/msba2-common/drivers/include/uart0.h diff --git a/board/msba2/drivers/msba2-cc1100.c b/board/msba2-common/drivers/msba2-cc110x.c similarity index 86% rename from board/msba2/drivers/msba2-cc1100.c rename to board/msba2-common/drivers/msba2-cc110x.c index 726d58550..7d5a6b219 100644 --- a/board/msba2/drivers/msba2-cc1100.c +++ b/board/msba2-common/drivers/msba2-cc110x.c @@ -34,7 +34,7 @@ and the mailinglist (subscription via web site) * @author Thomas Hillebrandt * @version $Revision: 1781 $ * - * @note $Id: msba2-cc1100.c 1781 2010-01-26 13:39:36Z hillebra $ + * @note $Id: msba2-cc110x.c 1781 2010-01-26 13:39:36Z hillebra $ */ #include @@ -43,10 +43,10 @@ and the mailinglist (subscription via web site) #include #include // sys -#include "cc1100.h" -#include "arch_cc1100.h" -#include "cc1100_spi.h" -#include "gpioint.h" +#include +#include +#include +#include #define CC1100_GDO0 (FIO0PIN & BIT27) // read serial I/O (GDO0) #define CC1100_GDO1 (FIO1PIN & BIT23) // read serial I/O (GDO1) @@ -82,19 +82,19 @@ static int test_time(int code) { } #endif -int cc1100_get_gdo0(void) { +int cc110x_get_gdo0(void) { return CC1100_GDO0; } -int cc1100_get_gdo1(void) { +int cc110x_get_gdo1(void) { return CC1100_GDO1; } -int cc1100_get_gdo2(void) { +int cc110x_get_gdo2(void) { return CC1100_GDO2; } -void cc1100_spi_init(void) +void cc110x_spi_init(void) { // configure chip-select FIO1DIR |= BIT21; @@ -128,8 +128,7 @@ void cc1100_spi_init(void) } } -uint8_t -cc1100_txrx(uint8_t c) { +uint8_t cc110x_txrx(uint8_t c) { uint8_t result; SSP0DR = c; #ifdef DEBUG @@ -160,13 +159,13 @@ cc1100_txrx(uint8_t c) { return result; } -void cc1100_spi_cs(void) +void cc110x_spi_cs(void) { FIO1CLR = BIT21; } void -cc1100_spi_select(void) +cc110x_spi_select(void) { volatile int retry_count = 0; volatile int abort_count; @@ -200,44 +199,44 @@ cc1100_spi_select(void) } void -cc1100_spi_unselect(void) +cc110x_spi_unselect(void) { FIO1SET = BIT21; } -void cc1100_before_send(void) +void cc110x_before_send(void) { // Disable GDO2 interrupt before sending packet - cc1100_gdo2_disable(); + cc110x_gdo2_disable(); } -void cc1100_after_send(void) +void cc110x_after_send(void) { // Enable GDO2 interrupt after sending packet - cc1100_gdo2_enable(); + cc110x_gdo2_enable(); } -void cc1100_gdo0_enable(void) { - gpioint_set(0, BIT27, GPIOINT_RISING_EDGE, &cc1100_gdo0_irq); +void cc110x_gdo0_enable(void) { + gpioint_set(0, BIT27, GPIOINT_RISING_EDGE, &cc110x_gdo0_irq); } -void cc1100_gdo0_disable(void) { +void cc110x_gdo0_disable(void) { gpioint_set(0, BIT27, GPIOINT_DISABLE, NULL); } -void cc1100_gdo2_disable(void) { +void cc110x_gdo2_disable(void) { gpioint_set(0, BIT28, GPIOINT_DISABLE, NULL); } -void cc1100_gdo2_enable(void) { - gpioint_set(0, BIT28, GPIOINT_FALLING_EDGE, &cc1100_gdo2_irq); +void cc110x_gdo2_enable(void) { + gpioint_set(0, BIT28, GPIOINT_FALLING_EDGE, &cc110x_gdo2_irq); } -void cc1100_init_interrupts(void) +void cc110x_init_interrupts(void) { // Enable external interrupt on low edge (for GDO2) FIO0DIR &= ~BIT28; - cc1100_gdo2_enable(); + cc110x_gdo2_enable(); // Enable external interrupt on low edge (for GDO0) FIO0DIR &= ~BIT27; } diff --git a/board/msba2/drivers/msba2-ltc4150.c b/board/msba2-common/drivers/msba2-ltc4150.c similarity index 86% rename from board/msba2/drivers/msba2-ltc4150.c rename to board/msba2-common/drivers/msba2-ltc4150.c index c590dee8d..4e6534c02 100644 --- a/board/msba2/drivers/msba2-ltc4150.c +++ b/board/msba2-common/drivers/msba2-ltc4150.c @@ -45,19 +45,19 @@ and the mailinglist (subscription via web site) #include "ltc4150_arch.h" #include "gpioint.h" -void ltc4150_disable_int(void) { +void __attribute__((__no_instrument_function__)) ltc4150_disable_int(void) { gpioint_set(0, BIT4, GPIOINT_DISABLE, NULL); } -void ltc4150_enable_int(void) { +void __attribute__((__no_instrument_function__)) ltc4150_enable_int(void) { gpioint_set(0, BIT4, GPIOINT_FALLING_EDGE, <c4150_interrupt); } -void ltc4150_sync_blocking(void) { +void __attribute__((__no_instrument_function__)) ltc4150_sync_blocking(void) { while(!(FIO0PIN & BIT4)) {}; } -void ltc4150_arch_init() { +void __attribute__((__no_instrument_function__)) ltc4150_arch_init() { FIO0DIR |= BIT5; FIO0SET = BIT5; } diff --git a/board/msba2/drivers/msba2-uart0.c b/board/msba2-common/drivers/msba2-uart0.c similarity index 95% rename from board/msba2/drivers/msba2-uart0.c rename to board/msba2-common/drivers/msba2-uart0.c index 8ff7e11e3..31a9870aa 100644 --- a/board/msba2/drivers/msba2-uart0.c +++ b/board/msba2-common/drivers/msba2-uart0.c @@ -35,6 +35,7 @@ and the mailinglist (subscription via web site) #include #include "lpc23xx.h" #include "VIC.h" +#include #include @@ -48,13 +49,13 @@ and the mailinglist (subscription via web site) * @note $Id$ */ -typedef struct toprint { +typedef struct toprint_t { unsigned int len; char content[]; -}toprint; +}toprint_t; #define QUEUESIZE 255 -static volatile toprint* queue[QUEUESIZE]; +static volatile toprint_t* queue[QUEUESIZE]; static volatile unsigned char queue_head = 0; static volatile unsigned char queue_tail = 0; static volatile unsigned char queue_items = 0; @@ -63,7 +64,7 @@ static volatile unsigned int actual_pos = 0; static volatile unsigned int running = 0; static volatile unsigned int fifo = 0; -static volatile toprint* actual = NULL; +static volatile toprint_t* actual = NULL; static inline void enqueue(void) { queue_items++; @@ -78,12 +79,14 @@ static inline void dequeue(void) { static void push_queue(void) { running = 1; + lpm_prevent_sleep |= LPM_PREVENT_SLEEP_UART; start: if (!actual) { if (queue_items) { dequeue(); } else { running = 0; + lpm_prevent_sleep &= ~LPM_PREVENT_SLEEP_UART; if (!fifo) while(!(U0LSR & BIT6)){}; return; diff --git a/board/msba2/drivers/include/hal-board.h b/board/msba2-common/include/msba2_common.h similarity index 74% rename from board/msba2/drivers/include/hal-board.h rename to board/msba2-common/include/msba2_common.h index a4dfc293a..fff12f965 100644 --- a/board/msba2/drivers/include/hal-board.h +++ b/board/msba2-common/include/msba2_common.h @@ -24,45 +24,28 @@ and the mailinglist (subscription via web site) scatterweb@lists.spline.inf.fu-berlin.de *******************************************************************************/ -#ifndef HALPLATFORM_H_ -#define HALPLATFORM_H_ +#ifndef __MSBA2_COMMON_H +#define __MSBA2_COMMON_H /** - * @ingroup msba2 + * @ingroup msb_a2 * @{ */ /** * @file - * @brief + * @brief MSB-A2 Common Board Definitions * * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project - * @author baar + * @author Kaspar Schleiser * @version $Revision$ * * @note $Id$ */ -#include "vdevice.h" -#include "device-gpio.h" -#include "device-rs232.h" -#include "device-serial.h" +#include -VDEVICE_NAME(vdevice_gpio, gpio_led_green); -VDEVICE_NAME(vdevice_gpio, gpio_led_red); -VDEVICE_NAME(vdevice_gpio, gpio_led_usb); - -/** - * @var tty0 - * @brief RS232 TTY0 device on UART0 - */ -VDEVICE_NAME(vdevice_rs232, tty0); - -/** - * @var console0 - * @brief console device on tty0 - */ -VDEVICE_NAME(vdevice_serial, console0); +#define VICIntEnClear VICIntEnClr /** @} */ -#endif /* HALPLATFORM_H_ */ +#endif // __MSBA2_COMMON_H diff --git a/board/msba2/lpc2387-timer3.c b/board/msba2-common/lpc2387-timer3.c similarity index 100% rename from board/msba2/lpc2387-timer3.c rename to board/msba2-common/lpc2387-timer3.c diff --git a/board/msba2/tools/CHANGES b/board/msba2-common/tools/CHANGES similarity index 100% rename from board/msba2/tools/CHANGES rename to board/msba2-common/tools/CHANGES diff --git a/board/msba2/tools/COPYING b/board/msba2-common/tools/COPYING similarity index 100% rename from board/msba2/tools/COPYING rename to board/msba2-common/tools/COPYING diff --git a/board/msba2/tools/Makefile b/board/msba2-common/tools/Makefile similarity index 96% rename from board/msba2/tools/Makefile rename to board/msba2-common/tools/Makefile index 91d44fdf7..e98492a30 100644 --- a/board/msba2/tools/Makefile +++ b/board/msba2-common/tools/Makefile @@ -12,9 +12,11 @@ PSEUDOTERM_OBJS = ${addprefix obj/,${patsubst %.c,%.o,$(PSEUDOTERM_SRC)}} TARGETDIR = bin lpc2k_pgm: $(OBJS) + mkdir -p $(TARGETDIR) $(CC) -o $(TARGETDIR)/lpc2k_pgm $(OBJS) pseudoterm: $(PSEUDOTERM_OBJS) + mkdir -p $(TARGETDIR) $(CC) -lpthread -o $(TARGETDIR)/pseudoterm $(PSEUDOTERM_OBJS) chipinfo.o: boot_2xxx.h boot_23xx.h diff --git a/board/msba2/tools/README.txt b/board/msba2-common/tools/README.txt similarity index 100% rename from board/msba2/tools/README.txt rename to board/msba2-common/tools/README.txt diff --git a/board/msba2/tools/armtools.txt b/board/msba2-common/tools/armtools.txt similarity index 100% rename from board/msba2/tools/armtools.txt rename to board/msba2-common/tools/armtools.txt diff --git a/board/msba2/tools/flash.cmd b/board/msba2-common/tools/flash.cmd similarity index 100% rename from board/msba2/tools/flash.cmd rename to board/msba2-common/tools/flash.cmd diff --git a/board/msba2/tools/flashutil.sh b/board/msba2-common/tools/flashutil.sh similarity index 100% rename from board/msba2/tools/flashutil.sh rename to board/msba2-common/tools/flashutil.sh diff --git a/board/msba2/tools/mkbootc b/board/msba2-common/tools/mkbootc similarity index 100% rename from board/msba2/tools/mkbootc rename to board/msba2-common/tools/mkbootc diff --git a/board/msba2/tools/mkstaticlist b/board/msba2-common/tools/mkstaticlist similarity index 100% rename from board/msba2/tools/mkstaticlist rename to board/msba2-common/tools/mkstaticlist diff --git a/board/msba2/tools/obj/boot_23xx.d b/board/msba2-common/tools/obj/boot_23xx.d similarity index 100% rename from board/msba2/tools/obj/boot_23xx.d rename to board/msba2-common/tools/obj/boot_23xx.d diff --git a/board/msba2/tools/obj/boot_2xxx.d b/board/msba2-common/tools/obj/boot_2xxx.d similarity index 100% rename from board/msba2/tools/obj/boot_2xxx.d rename to board/msba2-common/tools/obj/boot_2xxx.d diff --git a/board/msba2/tools/obj/chipinfo.d b/board/msba2-common/tools/obj/chipinfo.d similarity index 100% rename from board/msba2/tools/obj/chipinfo.d rename to board/msba2-common/tools/obj/chipinfo.d diff --git a/board/msba2/tools/obj/control_2xxx.d b/board/msba2-common/tools/obj/control_2xxx.d similarity index 100% rename from board/msba2/tools/obj/control_2xxx.d rename to board/msba2-common/tools/obj/control_2xxx.d diff --git a/board/msba2/tools/obj/download.d b/board/msba2-common/tools/obj/download.d similarity index 100% rename from board/msba2/tools/obj/download.d rename to board/msba2-common/tools/obj/download.d diff --git a/board/msba2/tools/obj/ihex.d b/board/msba2-common/tools/obj/ihex.d similarity index 100% rename from board/msba2/tools/obj/ihex.d rename to board/msba2-common/tools/obj/ihex.d diff --git a/board/msba2/tools/obj/lpc2k_pgm.d b/board/msba2-common/tools/obj/lpc2k_pgm.d similarity index 100% rename from board/msba2/tools/obj/lpc2k_pgm.d rename to board/msba2-common/tools/obj/lpc2k_pgm.d diff --git a/board/msba2/tools/obj/pseudoterm.d b/board/msba2-common/tools/obj/pseudoterm.d similarity index 100% rename from board/msba2/tools/obj/pseudoterm.d rename to board/msba2-common/tools/obj/pseudoterm.d diff --git a/board/msba2/tools/obj/serial.d b/board/msba2-common/tools/obj/serial.d similarity index 100% rename from board/msba2/tools/obj/serial.d rename to board/msba2-common/tools/obj/serial.d diff --git a/board/msba2/tools/obj/uuencode.d b/board/msba2-common/tools/obj/uuencode.d similarity index 100% rename from board/msba2/tools/obj/uuencode.d rename to board/msba2-common/tools/obj/uuencode.d diff --git a/board/msba2/tools/src/Jamfile b/board/msba2-common/tools/src/Jamfile similarity index 100% rename from board/msba2/tools/src/Jamfile rename to board/msba2-common/tools/src/Jamfile diff --git a/board/msba2/tools/src/boot.h b/board/msba2-common/tools/src/boot.h similarity index 100% rename from board/msba2/tools/src/boot.h rename to board/msba2-common/tools/src/boot.h diff --git a/board/msba2/tools/src/boot_23xx.armasm b/board/msba2-common/tools/src/boot_23xx.armasm similarity index 100% rename from board/msba2/tools/src/boot_23xx.armasm rename to board/msba2-common/tools/src/boot_23xx.armasm diff --git a/board/msba2/tools/src/boot_23xx.c b/board/msba2-common/tools/src/boot_23xx.c similarity index 100% rename from board/msba2/tools/src/boot_23xx.c rename to board/msba2-common/tools/src/boot_23xx.c diff --git a/board/msba2/tools/src/boot_23xx.h b/board/msba2-common/tools/src/boot_23xx.h similarity index 100% rename from board/msba2/tools/src/boot_23xx.h rename to board/msba2-common/tools/src/boot_23xx.h diff --git a/board/msba2/tools/src/boot_2xxx.armasm b/board/msba2-common/tools/src/boot_2xxx.armasm similarity index 100% rename from board/msba2/tools/src/boot_2xxx.armasm rename to board/msba2-common/tools/src/boot_2xxx.armasm diff --git a/board/msba2/tools/src/boot_2xxx.c b/board/msba2-common/tools/src/boot_2xxx.c similarity index 100% rename from board/msba2/tools/src/boot_2xxx.c rename to board/msba2-common/tools/src/boot_2xxx.c diff --git a/board/msba2/tools/src/boot_2xxx.h b/board/msba2-common/tools/src/boot_2xxx.h similarity index 100% rename from board/msba2/tools/src/boot_2xxx.h rename to board/msba2-common/tools/src/boot_2xxx.h diff --git a/board/msba2/tools/src/chipinfo.c b/board/msba2-common/tools/src/chipinfo.c similarity index 100% rename from board/msba2/tools/src/chipinfo.c rename to board/msba2-common/tools/src/chipinfo.c diff --git a/board/msba2/tools/src/chipinfo.h b/board/msba2-common/tools/src/chipinfo.h similarity index 100% rename from board/msba2/tools/src/chipinfo.h rename to board/msba2-common/tools/src/chipinfo.h diff --git a/board/msba2/tools/src/cksum_test.c b/board/msba2-common/tools/src/cksum_test.c similarity index 100% rename from board/msba2/tools/src/cksum_test.c rename to board/msba2-common/tools/src/cksum_test.c diff --git a/board/msba2/tools/src/control_2xxx.c b/board/msba2-common/tools/src/control_2xxx.c similarity index 100% rename from board/msba2/tools/src/control_2xxx.c rename to board/msba2-common/tools/src/control_2xxx.c diff --git a/board/msba2/tools/src/control_2xxx.h b/board/msba2-common/tools/src/control_2xxx.h similarity index 100% rename from board/msba2/tools/src/control_2xxx.h rename to board/msba2-common/tools/src/control_2xxx.h diff --git a/board/msba2/tools/src/download.c b/board/msba2-common/tools/src/download.c similarity index 100% rename from board/msba2/tools/src/download.c rename to board/msba2-common/tools/src/download.c diff --git a/board/msba2/tools/src/download.h b/board/msba2-common/tools/src/download.h similarity index 100% rename from board/msba2/tools/src/download.h rename to board/msba2-common/tools/src/download.h diff --git a/board/msba2/tools/src/gui.c b/board/msba2-common/tools/src/gui.c similarity index 100% rename from board/msba2/tools/src/gui.c rename to board/msba2-common/tools/src/gui.c diff --git a/board/msba2/tools/src/gui.h b/board/msba2-common/tools/src/gui.h similarity index 100% rename from board/msba2/tools/src/gui.h rename to board/msba2-common/tools/src/gui.h diff --git a/board/msba2/tools/src/ihex.c b/board/msba2-common/tools/src/ihex.c similarity index 100% rename from board/msba2/tools/src/ihex.c rename to board/msba2-common/tools/src/ihex.c diff --git a/board/msba2/tools/src/ihex.h b/board/msba2-common/tools/src/ihex.h similarity index 100% rename from board/msba2/tools/src/ihex.h rename to board/msba2-common/tools/src/ihex.h diff --git a/board/msba2/tools/src/lpc2k_pgm.c b/board/msba2-common/tools/src/lpc2k_pgm.c similarity index 99% rename from board/msba2/tools/src/lpc2k_pgm.c rename to board/msba2-common/tools/src/lpc2k_pgm.c index 153fa9b42..4891c5594 100644 --- a/board/msba2/tools/src/lpc2k_pgm.c +++ b/board/msba2-common/tools/src/lpc2k_pgm.c @@ -78,8 +78,6 @@ int main(int argc, char **argv) char* port_name = argv[1]; char* file_name = argv[2]; - sleep(1); - if (open_serial_port(port_name) < 0) { return(1); } diff --git a/board/msba2/tools/src/lpc2k_pgm.h b/board/msba2-common/tools/src/lpc2k_pgm.h similarity index 100% rename from board/msba2/tools/src/lpc2k_pgm.h rename to board/msba2-common/tools/src/lpc2k_pgm.h diff --git a/board/msba2/tools/src/pseudoterm.c b/board/msba2-common/tools/src/pseudoterm.c similarity index 100% rename from board/msba2/tools/src/pseudoterm.c rename to board/msba2-common/tools/src/pseudoterm.c diff --git a/board/msba2/tools/src/serial.c b/board/msba2-common/tools/src/serial.c similarity index 100% rename from board/msba2/tools/src/serial.c rename to board/msba2-common/tools/src/serial.c diff --git a/board/msba2/tools/src/serial.h b/board/msba2-common/tools/src/serial.h similarity index 100% rename from board/msba2/tools/src/serial.h rename to board/msba2-common/tools/src/serial.h diff --git a/board/msba2/tools/src/settings.c b/board/msba2-common/tools/src/settings.c similarity index 100% rename from board/msba2/tools/src/settings.c rename to board/msba2-common/tools/src/settings.c diff --git a/board/msba2/tools/src/settings.h b/board/msba2-common/tools/src/settings.h similarity index 100% rename from board/msba2/tools/src/settings.h rename to board/msba2-common/tools/src/settings.h diff --git a/board/msba2/tools/src/uuencode.c b/board/msba2-common/tools/src/uuencode.c similarity index 100% rename from board/msba2/tools/src/uuencode.c rename to board/msba2-common/tools/src/uuencode.c diff --git a/board/msba2/tools/src/uuencode.h b/board/msba2-common/tools/src/uuencode.h similarity index 100% rename from board/msba2/tools/src/uuencode.h rename to board/msba2-common/tools/src/uuencode.h diff --git a/board/msba2/tools/termctrl.sh b/board/msba2-common/tools/termctrl.sh similarity index 100% rename from board/msba2/tools/termctrl.sh rename to board/msba2-common/tools/termctrl.sh diff --git a/board/msba2/Jamfile b/board/msba2/Jamfile index 88106e45c..6e74471b6 100644 --- a/board/msba2/Jamfile +++ b/board/msba2/Jamfile @@ -25,11 +25,10 @@ # ****************************************************************************** # $Id$ -SubDir TOP board msba2 ; +SubDir TOP board $(BOARD) ; -Module board : board_init.c ; +Module board : board_init.c : board_common board_uart ; UseModule board ; -UseModule board_common ; -SubInclude TOP board $(BOARD) drivers ; +SubInclude TOP board $(BOARD)-common ; SubInclude TOP cpu $(CPU) ; diff --git a/board/msba2/Jamrules.msba2 b/board/msba2/Jamrules.msba2 index 5111de74d..22c8a8806 100644 --- a/board/msba2/Jamrules.msba2 +++ b/board/msba2/Jamrules.msba2 @@ -1,33 +1 @@ -# ****************************************************************************** -# Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved. -# -# These sources were developed at the Freie Universitaet Berlin, Computer -# Systems and Telematics group (http://cst.mi.fu-berlin.de). -# ------------------------------------------------------------------------------ -# This file is part of FeuerWare. -# -# This program is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, either version 3 of the License, or (at your option) any later -# version. -# -# FeuerWare is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along with -# this program. If not, see http://www.gnu.org/licenses/ . -# ------------------------------------------------------------------------------ -# For further information and questions please use the web site -# http://scatterweb.mi.fu-berlin.de -# and the mailinglist (subscription via web site) -# scatterweb@lists.spline.inf.fu-berlin.de -# ****************************************************************************** -# $Id$ - -CPU = lpc2387 ; - -HDRS += [ FPath $(TOP) board $(BOARD) drivers include ] ; - -FLASHER ?= $(POSIXSHELL) $(TOP)/board/msba2/tools/flashutil.sh ; -FLASHFLAGS ?= --basedir $(TOP)/board/msba2/tools --id "MSB-A2" --ports "$(PORT)" ; +include board/msba2-common/Jamrules.msba2 ; diff --git a/board/msba2/board_init.c b/board/msba2/board_init.c index 44c6cc33a..f250109c0 100644 --- a/board/msba2/board_init.c +++ b/board/msba2/board_init.c @@ -1,123 +1,23 @@ -/****************************************************************************** -Copyright 2008-2009, Freie Universitaet Berlin (FUB). All rights reserved. - -These sources were developed at the Freie Universitaet Berlin, Computer Systems -and Telematics group (http://cst.mi.fu-berlin.de). -------------------------------------------------------------------------------- -This file is part of FeuerWare. - -This program is free software: you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation, either version 3 of the License, or (at your option) any later -version. - -FeuerWare is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program. If not, see http://www.gnu.org/licenses/ . --------------------------------------------------------------------------------- -For further information and questions please use the web site - http://scatterweb.mi.fu-berlin.de -and the mailinglist (subscription via web site) - scatterweb@lists.spline.inf.fu-berlin.de -*******************************************************************************/ - -/** - * @ingroup msba2 - * @{ - */ - -/** - * @file - * @brief MSB-A2 board initialization - * - * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project - * @author Heiko Will - * @author Kaspar Schleiser - * @author Michael Baar - * - * @note $Id$ - */ #include -#include -#include "VIC.h" -#include "cpu.h" - -#define PCRTC BIT9 -#define CL_CPU_DIV 4 - -/*---------------------------------------------------------------------------*/ -/** - * @brief Enabling MAM and setting number of clocks used for Flash memory fetch - * @internal - */ -static void -init_mam(void) -{ - MAMCR = 0x0000; - MAMTIM = 0x0003; - MAMCR = 0x0002; -} -/*---------------------------------------------------------------------------*/ -static inline void -pllfeed(void) -{ - PLLFEED = 0xAA; - PLLFEED = 0x55; -} -/*---------------------------------------------------------------------------*/ -void init_clks1(void) -{ - // Disconnect PLL - PLLCON &= ~0x0002; - pllfeed(); - - // Disable PLL - PLLCON &= ~0x0001; - pllfeed(); +#include - SCS |= 0x20; // Enable main OSC - while( !(SCS & 0x40) ); // Wait until main OSC is usable - - /* select main OSC, 16MHz, as the PLL clock source */ - CLKSRCSEL = 0x0001; - - // Setting Multiplier and Divider values - PLLCFG = 0x0008; // M=9 N=1 Fcco = 288 MHz - pllfeed(); - - // Enabling the PLL */ - PLLCON = 0x0001; - pllfeed(); - - /* Set clock divider to 4 (value+1) */ - CCLKCFG = CL_CPU_DIV - 1; // Fcpu = 72 MHz - -#if USE_USB - USBCLKCFG = USBCLKDivValue; /* usbclk = 288 MHz/6 = 48 MHz */ -#endif +void loop_delay(void) { + volatile uint16_t i, j; + for (i = 1; i < 30; i++) { + for (j = 1; j != 0; j++) { + asm volatile (" nop "); + } + } } -void init_clks2(void){ - // Wait for the PLL to lock to set frequency - while(!(PLLSTAT & BIT26)); - - // Connect the PLL as the clock source - PLLCON = 0x0003; - pllfeed(); - - /* Check connect bit status */ - while (!(PLLSTAT & BIT25)); -} +void bl_blink(void) { + LED_RED_ON; + LED_GREEN_ON; + + loop_delay(); -void bl_init_clks(void) -{ - PCONP = PCRTC; // switch off everything except RTC - init_clks1(); - init_clks2(); - init_mam(); + LED_RED_OFF; + LED_GREEN_OFF; } void bl_init_ports(void) @@ -133,24 +33,8 @@ void bl_init_ports(void) FIO3DIR |= LED_GREEN_PIN; LED_RED_OFF; LED_GREEN_OFF; -} - -void loop_delay(void) { - volatile uint16_t i, j; - for (i = 1; i < 30; i++) { - for (j = 1; j != 0; j++) { - asm volatile (" nop "); - } - } -} - -void bl_blink(void) { - LED_RED_ON; - LED_GREEN_ON; - loop_delay(); - - LED_RED_OFF; - LED_GREEN_OFF; + /* short blinking of both of the LEDs on startup */ + bl_blink(); } diff --git a/board/msba2/drivers/Jamfile b/board/msba2/drivers/Jamfile deleted file mode 100644 index 0b750d947..000000000 --- a/board/msba2/drivers/Jamfile +++ /dev/null @@ -1,7 +0,0 @@ -SubDir TOP board msba2 drivers ; - -Module board_cc1100 : msba2-cc1100.c ; -Module board_hal : msba2-hal.c ; -Module board_ltc4150 : msba2-ltc4150.c : gpioint ; -Module board_common : msba2-uart0.c : ringbuffer ; -Module board_uart : msba2-uart0_thread.c : chardev_thread ringbuffer ; diff --git a/board/msba2/include/board.h b/board/msba2/include/board.h index 4356e4423..2b1f28fd2 100644 --- a/board/msba2/include/board.h +++ b/board/msba2/include/board.h @@ -1,51 +1,8 @@ -/****************************************************************************** -Copyright 2008, Freie Universitaet Berlin (FUB). All rights reserved. - -These sources were developed at the Freie Universitaet Berlin, Computer Systems -and Telematics group (http://cst.mi.fu-berlin.de). -------------------------------------------------------------------------------- -This file is part of FeuerWare. - -This program is free software: you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation, either version 3 of the License, or (at your option) any later -version. - -FeuerWare is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program. If not, see http://www.gnu.org/licenses/ . --------------------------------------------------------------------------------- -For further information and questions please use the web site - http://scatterweb.mi.fu-berlin.de -and the mailinglist (subscription via web site) - scatterweb@lists.spline.inf.fu-berlin.de -*******************************************************************************/ - #ifndef __BOARD_H -#define __BOARD_H - -/** - * @ingroup msb_a2 - * @{ - */ - -/** - * @file - * @brief MSB-A2 Board - * - * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project - * @author Kaspar Schleiser - * @version $Revision$ - * - * @note $Id$ - */ - -#include +#define __BOARD_H -#define VICIntEnClear VICIntEnClr +#include +#include #define LED_RED_PIN (BIT25) #define LED_GREEN_PIN (BIT26) @@ -58,5 +15,4 @@ and the mailinglist (subscription via web site) #define LED_RED_ON (FIO3CLR = LED_RED_PIN) #define LED_RED_TOGGLE (FIO3PIN ^= LED_RED_PIN) -/** @} */ -#endif // __BOARD_H +#endif /* __BOARD_H */ diff --git a/board/olimex_lpc2148/tick.c b/board/olimex_lpc2148/tick.c index 08b3dcb0b..4b8912607 100644 --- a/board/olimex_lpc2148/tick.c +++ b/board/olimex_lpc2148/tick.c @@ -51,12 +51,12 @@ int counter = 0; void Timer0_IRQHandler (void) { - extern unsigned int fk_context_switch_request; + extern unsigned int sched_context_switch_request; counter++; T0IR |= 0xff; // reset timer1 interrupt flag sl_printf("#"); - fk_context_switch_request = 1; + sched_context_switch_request = 1; VICVectAddr = 0; // acknowledge interrupt (if using VIC IRQ) } diff --git a/board/pttu/Jamfile b/board/pttu/Jamfile index a7b4d6df1..11b4a77e7 100644 --- a/board/pttu/Jamfile +++ b/board/pttu/Jamfile @@ -23,13 +23,12 @@ # and the mailinglist (subscription via web site) # scatterweb@lists.spline.inf.fu-berlin.de # ****************************************************************************** -# $Id: Jamfile 922 2009-03-26 12:52:27Z baar $ +# $Id$ -SubDir TOP board pttu ; +SubDir TOP board $(BOARD) ; -Module board : board_init.c ; +Module board : board_init.c : board_common board_uart ; UseModule board ; -UseModule board_common ; -SubInclude TOP board $(BOARD) drivers ; +SubInclude TOP board msba2-common ; SubInclude TOP cpu $(CPU) ; diff --git a/board/pttu/Jamrules.pttu b/board/pttu/Jamrules.pttu index 7eff15f0b..53e71c71f 100644 --- a/board/pttu/Jamrules.pttu +++ b/board/pttu/Jamrules.pttu @@ -25,13 +25,10 @@ # ****************************************************************************** # $Id: Jamrules.msba2 881 2009-03-20 12:24:58Z kaspar $ -CPU = lpc2387 ; +include board/msba2-common/Jamrules.msba2 ; HDRS += [ FPath $(TOP) board $(BOARD) drivers include ] ; -FLASHER = $(POSIXSHELL) $(TOP)/board/msba2/tools/flashutil.sh ; -FLASHFLAGS = --basedir $(TOP)/board/msba2/tools --id PTTU --ports "$(PORT)" --openocd $(TOP)/board/pttu/tools/openocd-pttu.sh --openocd-if $(OPENOCD_IF) ; - GDB = arm-elf-gdb ; GDBFLAGS = -x board/pttu/tools/pttu_debug.gdb ; diff --git a/board/pttu/board_init.c b/board/pttu/board_init.c index 3070bdfce..b5b78bde2 100644 --- a/board/pttu/board_init.c +++ b/board/pttu/board_init.c @@ -33,94 +33,18 @@ and the mailinglist (subscription via web site) * @file * @brief PTTU board initialization * - * @author Freie Universit�t Berlin, Computer Systems & Telematics, FeuerWhere project + * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project * @author Heiko Will - * @author Kaspar Schleise - * @author Michael Baar + * @author Kaspar Schleiser * - * @note $Id: cmdengine-out.c 971 2009-04-07 13:41:36Z baar $ */ -#include "lpc23xx.h" -#include "VIC.h" -#include "cpu.h" +#include +#include +#include #define PCRTC BIT9 #define CL_CPU_DIV 4 -/*---------------------------------------------------------------------------*/ -/** - * @brief Enabling MAM and setting number of clocks used for Flash memory fetch - * @internal - */ -void -init_mam(void) -{ - MAMCR = 0x0000; - MAMTIM = 0x0003; - MAMCR = 0x0002; -} -/*---------------------------------------------------------------------------*/ -static inline void -pllfeed(void) -{ - PLLFEED = 0xAA; - PLLFEED = 0x55; -} -/*---------------------------------------------------------------------------*/ -void init_clks1(void) -{ - // Disconnect PLL - PLLCON &= ~0x0002; - pllfeed(); - - // Disable PLL - PLLCON &= ~0x0001; - pllfeed(); - - SCS |= 0x20; // Enable main OSC - while( !(SCS & 0x40) ); // Wait until main OSC is usable - - /* select main OSC, 16MHz, as the PLL clock source */ - CLKSRCSEL = 0x0001; - - // Setting Multiplier and Divider values - PLLCFG = 0x0008; // M=9 N=1 Fcco = 288 MHz - pllfeed(); - - // Enabling the PLL */ - PLLCON = 0x0001; - pllfeed(); - - /* Set clock divider to 4 (value+1) */ - CCLKCFG = CL_CPU_DIV - 1; // Fcpu = 72 MHz - -#if USE_USB - USBCLKCFG = USBCLKDivValue; /* usbclk = 288 MHz/6 = 48 MHz */ -#endif -} - -void init_clks2(void){ - // Wait for the PLL to lock to set frequency - while(!(PLLSTAT & BIT26)); - - // Connect the PLL as the clock source - PLLCON = 0x0003; - pllfeed(); - - /* Check connect bit status */ - while (!(PLLSTAT & BIT25)); -} - -void bl_init_clks(void) -{ - PCONP = PCRTC; // switch off everything except RTC - init_clks1(); - init_clks2(); - init_mam(); -} - - -// Michael, Do not change anything here! even not the redundant parts! void bl_init_ports(void) { SCS |= BIT0; // Set IO Ports to fast switching mode diff --git a/board/pttu/drivers/Jamfile b/board/pttu/drivers/Jamfile index 26a8b7c2a..31d6db1d6 100644 --- a/board/pttu/drivers/Jamfile +++ b/board/pttu/drivers/Jamfile @@ -1,4 +1,2 @@ SubDir TOP board pttu drivers ; -Module board_common : pttu-uart0.c ; - diff --git a/board/pttu/drivers/pttu-uart0.c b/board/pttu/drivers/pttu-uart0.c deleted file mode 100644 index d542f2260..000000000 --- a/board/pttu/drivers/pttu-uart0.c +++ /dev/null @@ -1,204 +0,0 @@ -/****************************************************************************** -Copyright 2008-2009, Freie Universitaet Berlin (FUB). All rights reserved. - -These sources were developed at the Freie Universitaet Berlin, Computer Systems -and Telematics group (http://cst.mi.fu-berlin.de). -------------------------------------------------------------------------------- -This file is part of FeuerWare. - -This program is free software: you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation, either version 3 of the License, or (at your option) any later -version. - -FeuerWare is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program. If not, see http://www.gnu.org/licenses/ . --------------------------------------------------------------------------------- -For further information and questions please use the web site - http://scatterweb.mi.fu-berlin.de -and the mailinglist (subscription via web site) - scatterweb@lists.spline.inf.fu-berlin.de -*******************************************************************************/ - -/* - * debug_uart.c: provides initial serial debug output - * - * Copyright (C) 2008, 2009 Kaspar Schleiser - * Heiko Will - */ -#include -#include -#include -#include "lpc23xx.h" -#include "VIC.h" - -/** - * @file - * @ingroup lpc2387 - * - * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project - * @version $Revision$ - * - * @note $Id$ - */ - -typedef struct toprint { - unsigned int len; - char content[]; -}toprint; - -#define QUEUESIZE 255 -static volatile toprint* queue[QUEUESIZE]; -static volatile unsigned char queue_head = 0; -static volatile unsigned char queue_tail = 0; -static volatile unsigned char queue_items = 0; - -static volatile unsigned int actual_pos = 0; -static volatile unsigned int running = 0; -static volatile unsigned int fifo = 0; - -static volatile toprint* actual = NULL; -void (*uart0_callback)(int); - -static inline void enqueue(void) { - queue_items++; - queue_tail++; -} - -static inline void dequeue(void) { - actual = (queue[queue_head]); - queue_items--; - queue_head++; -} - -static void push_queue(void) { - running = 1; -start: - if (!actual) { - if (queue_items) { - dequeue(); - } else { - running = 0; - if (!fifo) - while(!(U0LSR & BIT6)){}; - return; - } - } - while ((actual_pos < actual->len) && (fifo++ < 16)){ - U0THR = actual->content[actual_pos++]; - } - if (actual_pos == actual->len) { - free((void*)actual); - actual = NULL; - actual_pos = 0; - goto start; - } -} - -int uart_active(void){ - return (running || fifo); -} - -static inline void receive(int c) -{ - if (uart0_callback != NULL) uart0_callback(c); -} - -void stdio_flush(void) -{ - U0IER &= ~BIT1; // disable THRE interrupt - while(running) { - while(!(U0LSR & (BIT5|BIT6))){}; // transmit fifo - fifo=0; - push_queue(); // dequeue to fifo - } - U0IER |= BIT1; // enable THRE interrupt -} - -void UART0_IRQHandler(void) __attribute__((interrupt("IRQ"))); -void UART0_IRQHandler(void) -{ - int iir; - iir = U0IIR; - - switch(iir & UIIR_ID_MASK) { - case UIIR_THRE_INT: // Transmit Holding Register Empty - fifo=0; - push_queue(); - break; - - case UIIR_CTI_INT: // Character Timeout Indicator - case UIIR_RDA_INT: // Receive Data Available - do { - int c = U0RBR; - receive(c); - } while (U0LSR & ULSR_RDR); - break; - - default: - U0LSR; - U0RBR; - break; - } // switch - VICVectAddr = 0; // Acknowledge Interrupt -} - -static inline int uart0_puts(char *astring,int length) -{ - while (queue_items == (QUEUESIZE-1)) {} ; - U0IER = 0; - queue[queue_tail] = malloc(length+sizeof(unsigned int)); - queue[queue_tail]->len = length; - memcpy(&queue[queue_tail]->content,astring,length); - enqueue(); - if (!running) - push_queue(); - U0IER |= BIT0 | BIT1; // enable RX irq - - // alternative without queue: -// int i; -// for (i=0;iconfig->speed - /* - * Baudrate calculation - * BR = PCLK (9 MHz) / (16 x 256 x DLM + DLL) x (1/(DIVADDVAL/MULVAL)) - */ - U0FDR = 0x92; // DIVADDVAL = 0010 = 2, MULVAL = 1001 = 9 - U0DLM = 0x00; - U0DLL = 0x04; - - U0LCR = 0x03; // DLAB = 0 - U0FCR = 0x07; // Enable and reset TX and RX FIFO - - /* irq */ - install_irq(UART0_INT, UART0_IRQHandler, 6); - U0IER |= BIT0 | BIT1; // enable RX+TX irq - return 1; -} - diff --git a/core/Jamfile b/core/Jamfile index 64862e7ed..becba93e2 100644 --- a/core/Jamfile +++ b/core/Jamfile @@ -27,8 +27,8 @@ SubDir TOP core ; -Module core : kernel_init.c scheduler.c mutex.c msg.c queue.c - clist.c thread.c bitarithm.c ; +Module core : kernel_init.c sched.c mutex.c msg.c thread.c : core_lib ; +Module core_lib : queue.c clist.c bitarithm.c cib.c lifo.c ; Module hwtimer : hwtimer.c : hwtimer_cpu ; diff --git a/core/bitarithm.c b/core/bitarithm.c index bf9ee8699..7ffd03140 100644 --- a/core/bitarithm.c +++ b/core/bitarithm.c @@ -15,8 +15,6 @@ #include -#define ARCH_32_BIT (__INT_MAX__ == 2147483647) - unsigned number_of_highest_bit(unsigned v) { diff --git a/core/cib.c b/core/cib.c new file mode 100644 index 000000000..b588fe671 --- /dev/null +++ b/core/cib.c @@ -0,0 +1,43 @@ +#include + +void cib_init(cib_t *cib, unsigned int size) { + cib->read_count = 0; + cib->write_count = 0; + cib->complement = 0-size; +} + +int cib_avail (cib_t *cib) { + return cib->write_count - cib->read_count; +} + +int cib_get(cib_t *cib) { + int avail = cib_avail (cib); + + if (avail > 0) { + return cib->read_count++ & ~cib->complement; + } + + return -1; +} + +int cib_put(cib_t *cib) { + int avail = cib_avail (cib); + + if ((int)(avail + cib->complement) < 0 ) { + return cib->write_count++ & ~(cib->complement); + } + + return -1; +} + +/* +int main() { + cib_t cib; + + cib_init(&cib, 0); + + int res = cib_get(&cib); + + printf("%i\n", res); +} +*/ diff --git a/core/hwtimer.c b/core/hwtimer.c index 01600a4f7..b4cdf0727 100644 --- a/core/hwtimer.c +++ b/core/hwtimer.c @@ -16,77 +16,37 @@ */ #include -#include "hwtimer.h" -#include "hwtimer_cpu.h" -#include "hwtimer_arch.h" +#include +#include +#include -#include - -#define USE_NONBLOCKING_WAIT 1 -#if USE_NONBLOCKING_WAIT -//#include -#include "kernel.h" -#include "mutex.h" -#endif +#include +#include +#include /*---------------------------------------------------------------------------*/ typedef struct hwtimer_t { void (*callback)(void*); void* data; - uint8_t checksum; } hwtimer_t; -#define HWTIMER_QUEUESIZE ARCH_MAXTIMERS -#define Q_FULL HWTIMER_QUEUESIZE + 1 - -static hwtimer_t timer[HWTIMER_QUEUESIZE]; -static int queue[HWTIMER_QUEUESIZE]; -static short queue_head = 0; -static short queue_tail = 0; -static short queue_items = 0; - -static uint8_t timer_id = 0; -static volatile long available_timers = 0; +static hwtimer_t timer[ARCH_MAXTIMERS]; +static int lifo[ARCH_MAXTIMERS+1]; /*---------------------------------------------------------------------------*/ -static int enqueue(int item) { - // Test if timer is already cleared: - // (hack to prevent race-condition with proccing timer (ISR) and manual hwtimer_remove) - if (available_timers & (1 << item)) { - return 1; - } - queue[queue_tail] = item; - available_timers |= (1 << item); - queue_tail = (queue_tail + 1) % HWTIMER_QUEUESIZE; - queue_items++; - if (queue_items == HWTIMER_QUEUESIZE) { - lpm_prevent_sleep &= ~LPM_PREVENT_SLEEP_HWTIMER; // Allow power down - } - return 1; -} - -static int dequeue(void) { - register int ret; - if (!queue_items) - return Q_FULL; - lpm_prevent_sleep |= LPM_PREVENT_SLEEP_HWTIMER; // No power down while a timer is active - queue_items--; - ret = queue[queue_head]; - queue[queue_head] = 0xff; // Mark as empty - available_timers &= ~(1 << ret); - queue_head = (queue_head + 1) % HWTIMER_QUEUESIZE; - return ret; -} - static void multiplexer(int source) { - enqueue(source); +// printf("\nhwt: trigger %i.\n", source); + lifo_insert(lifo, source); + lpm_prevent_sleep--; + timer[source].callback(timer[source].data); } -static void hwtimer_releasemutex(void* mutex) { - mutex_unlock((mutex_t*)mutex, true); +static void hwtimer_wakeup(void* ptr) { + int pid = (int)ptr; + thread_wakeup(pid); } void hwtimer_spin(unsigned long ticks) @@ -105,25 +65,18 @@ void hwtimer_init(void) { /*---------------------------------------------------------------------------*/ void hwtimer_init_comp(uint32_t fcpu) { - int i; - queue_head = 0; - queue_tail = 0; - queue_items = 0; - timer_id = 0; - available_timers = 0; hwtimer_arch_init(multiplexer, fcpu); - for (i = 0; i < HWTIMER_QUEUESIZE; i++) { - queue[i] = 0xff; // init queue as empty - } - for (i = 0; i < HWTIMER_QUEUESIZE; i++) { - enqueue(i); + + lifo_init(lifo, ARCH_MAXTIMERS); + for (int i = 0; i < ARCH_MAXTIMERS; i++) { + lifo_insert(lifo, i); } } /*---------------------------------------------------------------------------*/ int hwtimer_active(void) { - return queue_items != HWTIMER_QUEUESIZE; + return (! lifo_empty(lifo)); } /*---------------------------------------------------------------------------*/ @@ -137,49 +90,57 @@ unsigned long hwtimer_now(void) void hwtimer_wait(unsigned long ticks) { - mutex_t mutex; - if (ticks <= 4 || inISR()) { + if (ticks <= 6 || inISR()) { hwtimer_spin(ticks); return; } - mutex_init(&mutex); - mutex_lock(&mutex); - // -2 is to adjust the real value - int res = hwtimer_set(ticks-2, hwtimer_releasemutex, &mutex); + + /* -2 is to adjust the real value */ + int res = hwtimer_set(ticks-2, hwtimer_wakeup, (void*) (unsigned int)(active_thread->pid)); if (res == -1) { - mutex_unlock(&mutex, true); hwtimer_spin(ticks); return; } - mutex_lock(&mutex); + + thread_sleep(); } /*---------------------------------------------------------------------------*/ +#include static int _hwtimer_set(unsigned long offset, void (*callback)(void*), void *ptr, bool absolute) { - if (! inISR() ) dINT(); -// hwtimer_arch_disable_interrupt(); - int x = dequeue(); - if (x == Q_FULL) { - printf("[KT] no timers left\n"); -// hwtimer_arch_enable_interrupt(); - if (! inISR()) eINT(); + if (!inISR()) { + dINT(); + } + + int n = lifo_get(lifo); + if (n == -1) { + if (! inISR()) { + eINT(); + } + puts("No hwtimer left."); return -1; } - timer[x].callback = callback; - timer[x].data = ptr; - timer[x].checksum = ++timer_id; - - if (absolute) - hwtimer_arch_set_absolute(offset, x); - else - hwtimer_arch_set(offset, x); - - //hwtimer_arch_enable_interrupt(); - if (! inISR()) eINT(); - return (timer[x].checksum << 8) + x; + timer[n].callback = callback; + timer[n].data = ptr; + + if (absolute) { +// printf("hwt: setting %i to %u\n", n, offset); + hwtimer_arch_set_absolute(offset, n); + } + else { +// printf("hwt: setting %i to offset %u\n", n, offset); + hwtimer_arch_set(offset, n); + } + + lpm_prevent_sleep++; + + if (!inISR()) { + eINT(); + } + return n; } int hwtimer_set(unsigned long offset, void (*callback)(void*), void *ptr) { @@ -193,31 +154,18 @@ int hwtimer_set_absolute(unsigned long offset, void (*callback)(void*), void *pt /*---------------------------------------------------------------------------*/ -int hwtimer_remove(int x) +int hwtimer_remove(int n) { - int t = x & 0xff; - uint8_t checksum = (uint8_t) (x >> 8); - if (t < 0 || t >= HWTIMER_QUEUESIZE || timer[t].callback == NULL || timer[t].checksum != checksum) { - return -1; - } +// printf("hwt: remove %i.\n", n); hwtimer_arch_disable_interrupt(); - hwtimer_arch_unset(t); - enqueue(t); - timer[t].callback = NULL; + hwtimer_arch_unset(n); + + lifo_insert(lifo, n); + timer[n].callback = NULL; + + lpm_prevent_sleep--; + hwtimer_arch_enable_interrupt(); return 1; } -/*---------------------------------------------------------------------------*/ - -void hwtimer_debug(int timer) -{ - printf("queue size: %i\n", queue_items); - printf("available timers: %lu\n", available_timers); - int t = timer & 0xff; - if (available_timers & (1 << t)) { - printf("timer %i is: not set\n", timer); - } else { - printf("timer %i is: set\n", timer); - } -} diff --git a/core/include/bitarithm.h b/core/include/bitarithm.h index de06c5024..d159f3334 100644 --- a/core/include/bitarithm.h +++ b/core/include/bitarithm.h @@ -64,6 +64,8 @@ #endif /** @} */ +#define ARCH_32_BIT (__INT_MAX__ == 2147483647) + /** * @brief Returns the number of the highest '1' bit in a value * @param[in] v Input value diff --git a/core/include/cib.h b/core/include/cib.h new file mode 100644 index 000000000..7ef179280 --- /dev/null +++ b/core/include/cib.h @@ -0,0 +1,15 @@ +#ifndef __CIB_H +#define __CIB_H + +typedef struct cib_t { + unsigned int read_count; + unsigned int write_count; + unsigned int complement; +} cib_t; + +void cib_init(cib_t *cib, unsigned int size); +int cib_get(cib_t *cib); +int cib_put(cib_t *cib); +int cib_avail(cib_t *cib); + +#endif /* __CIB_H */ diff --git a/core/include/config.h b/core/include/config.h new file mode 100644 index 000000000..d320f8a4e --- /dev/null +++ b/core/include/config.h @@ -0,0 +1,27 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#include + +#define CONFIG_KEY (0x1701) + +extern char configmem[]; + +/* @brief: Stores configuration data of the node */ +typedef struct { + uint16_t id; ///< unique node identifier + uint8_t radio_address; ///< address for radio communication + uint8_t radio_channel; ///< current frequency +} config_t; + +/* @brief: Element to store in flashrom */ +typedef struct { + uint16_t magic_key; ///< validity check + config_t config; ///< the node's configuration +} configmem_t; + +extern config_t sysconfig; + +uint8_t config_save(void); + +#endif /* CONFIG_H */ diff --git a/core/include/flags.h b/core/include/flags.h index 97da2efa8..462133ef7 100644 --- a/core/include/flags.h +++ b/core/include/flags.h @@ -15,9 +15,9 @@ #ifndef _FLAGS_H #define _FLAGS_H -#define CREATE_WOUT_YIELD 4 #define CREATE_SLEEPING 1 -#define EXPECTS_REPLY 2 +#define AUTO_FREE 2 +#define CREATE_WOUT_YIELD 4 #define CREATE_STACKTEST 8 /** diff --git a/core/include/hwtimer.h b/core/include/hwtimer.h index 39f2c0f18..d17137ede 100644 --- a/core/include/hwtimer.h +++ b/core/include/hwtimer.h @@ -30,7 +30,7 @@ #define __HWTIMER_H #include -#include "hwtimer_cpu.h" +#include /** * @def HWTIMER_SPEED @@ -124,6 +124,7 @@ void hwtimer_t0_enable_interrupt(void); void hwtimer_t0_set(unsigned long value, short timer); void hwtimer_t0_unset(short timer); unsigned long hwtimer_t0_now(void); +unsigned long hwtimer_now(void); /** @} */ #endif /* __HWTIMER_H */ diff --git a/core/include/kernel.h b/core/include/kernel.h index 69e12e6dd..49dda3664 100644 --- a/core/include/kernel.h +++ b/core/include/kernel.h @@ -22,10 +22,11 @@ */ #include +#include "config.h" #include "tcb.h" #include "cpu.h" #include "flags.h" -#include "scheduler.h" +#include "sched.h" #include "cpu-conf.h" /* ------------------------------------------------------------------------- */ @@ -70,15 +71,7 @@ #define PRIORITY_MIN SCHED_PRIO_LEVELS-1 #define PRIORITY_IDLE PRIORITY_MIN -#define PRIORITY_MAIN PRIORITY_MIN-1 -#define PRIORITY_CMD_THREADS PRIORITY_MIN-2 ///< all cmd handler threads -#define PRIORITY_CBD PRIORITY_MIN-3 -#define PRIORITY_CMDD PRIORITY_MIN-4 ///< cmdengine demon -#define PRIORITY_PRINTTHREAD PRIORITY_MIN-5 ///< mprint worker thread -#define PRIORITY_HAL PRIORITY_MIN-6 -#define PRIORITY_UTIMER PRIORITY_MIN-7 -#define PRIORITY_MMREQ PRIORITY_MIN-8 -#define PRIORITY_CC1100 PRIORITY_MIN-9 +#define PRIORITY_MAIN (PRIORITY_MIN - (SCHED_PRIO_LEVELS/2)) /** * @brief Check whether called from interrupt service routine @@ -88,9 +81,12 @@ */ int inISR(void); +#define LPM_PREVENT_SLEEP_UART BIT2 #define LPM_PREVENT_SLEEP_HWTIMER BIT1 extern volatile int lpm_prevent_sleep; +extern config_t sysconfig; + /** @} */ #endif /* KERNEL_H_ */ diff --git a/core/include/kernel_intern.h b/core/include/kernel_intern.h index a58205319..7b5bd12c1 100644 --- a/core/include/kernel_intern.h +++ b/core/include/kernel_intern.h @@ -18,10 +18,10 @@ void kernel_init(void); void board_init_drivers(); -char *fk_stack_init(void *task_func, void *stack_start); -void fk_task_exit(void); -void fk_print_stack (); -int fk_measure_stack_free(char* stack); +char *thread_stack_init(void *task_func, void *stack_start); +void sched_task_exit(void); +void thread_print_stack (); +int thread_measure_stack_usage(char* stack); /** @} */ #endif /* KERNEL_INTERN_H_ */ diff --git a/core/include/lifo.h b/core/include/lifo.h new file mode 100644 index 000000000..524698a90 --- /dev/null +++ b/core/include/lifo.h @@ -0,0 +1,9 @@ +#ifndef __LIFO_H +#define __LIFO_H + +int lifo_empty(int *array); +void lifo_init(int *array, int n); +void lifo_insert(int *array, int i); +int lifo_get(int *array); + +#endif /* __LIFO_H */ diff --git a/core/include/msg.h b/core/include/msg.h index 4a0504c7f..ee3d0e9f7 100644 --- a/core/include/msg.h +++ b/core/include/msg.h @@ -1,4 +1,12 @@ /** + * There are two ways to use the IPC Messaging system of µkleos. The default is synchronous + * messaging. In this manner, messages are either dropped when the receiver is not waiting and the + * message was sent non-blocking, or will be delivered immediately when the receiver calls + * msg_receive(msg_t* m). To use asynchronous messaging any thread can create its own queue by + * calling msg_init_queue(msg_t* array, int num). Messages sent to a thread with a non full message + * queue are never dropped and the sending never blocks. Threads with a full message queue behaves + * like in synchronous mode. + * * @defgroup kernel_msg Messaging / IPC * @ingroup kernel * @{ @@ -35,7 +43,7 @@ typedef struct msg { char *ptr; ///< pointer content field uint32_t value; ///< value content field } content; -} msg; +} msg_t; /** @@ -48,13 +56,14 @@ typedef struct msg { * * @param m Pointer to message structure * @param target_pid PID of target thread - * @param block If true and receiver is not receive-blocked, function will block. If not, function returns. + * @param block If true and receiver is not receive-blocked, function will block. If not, function + * returns. * - * @return 1 if sending was successfull - * @return 0 if receiver is not waiting and block == false + * @return 1 if sending was successfull (message delivered directly or to a queue) + * @return 0 if receiver is not waiting or has a full message queue and block == false * @return -1 on error (invalid PID) */ -int msg_send(msg* m, unsigned int target_pid, bool block); +int msg_send(msg_t* m, unsigned int target_pid, bool block); /** @@ -68,7 +77,7 @@ int msg_send(msg* m, unsigned int target_pid, bool block); * @return 1 if sending was successfull * @return 0 if receiver is not waiting and block == false */ -int msg_send_int(msg* m, unsigned int target_pid); +int msg_send_int(msg_t* m, unsigned int target_pid); /** @@ -79,7 +88,7 @@ int msg_send_int(msg* m, unsigned int target_pid); * * @return 1 Function always succeeds or blocks forever. */ -int msg_receive(msg* m); +int msg_receive(msg_t* m); /** * @brief Send a message, block until reply received. @@ -90,7 +99,7 @@ int msg_receive(msg* m); * @param target pid the pid of the target process * @return 1 if successful */ -int msg_send_receive(msg *m, msg *reply, unsigned int target_pid); +int msg_send_receive(msg_t *m, msg_t *reply, unsigned int target_pid); /** * @brief Replies to a message. @@ -103,9 +112,15 @@ int msg_send_receive(msg *m, msg *reply, unsigned int target_pid); * @return 1 if succcessful * qreturn 0 on error */ -int msg_reply(msg *m, msg *reply); +int msg_reply(msg_t *m, msg_t *reply); -uint16_t msg_alloc_event(void); +/** + * @brief Initialize the current thread's message queue. + * + * @param array Pointer to preallocated array of msg objects + * @param num Number of msg objects in array. MUST BE POWER OF TWO! + */ +int msg_init_queue(msg_t* array, int num); /** @} */ #endif /* __MSG_H */ diff --git a/core/include/queue.h b/core/include/queue.h index d7a122e50..ae377409d 100644 --- a/core/include/queue.h +++ b/core/include/queue.h @@ -23,6 +23,7 @@ void queue_add_head(queue_node_t* root, queue_node_t* new_obj); queue_node_t *queue_remove_head(queue_node_t* root); void queue_priority_add(queue_node_t* root, queue_node_t* new_obj); void queue_priority_add_generic(queue_node_t* root, queue_node_t* new_obj, int(*cmp)(queue_node_t*,queue_node_t*)) ; +void queue_remove(queue_node_t* root, queue_node_t *node); /** @} */ #endif // __QUEUE_H diff --git a/core/include/scheduler.h b/core/include/sched.h similarity index 65% rename from core/include/scheduler.h rename to core/include/sched.h index afff055c9..9f9712249 100644 --- a/core/include/scheduler.h +++ b/core/include/sched.h @@ -15,24 +15,25 @@ #define MAXTHREADS 32 -#ifdef ARCH_32_BIT +#if ARCH_32_BIT #define SCHED_PRIO_LEVELS 32 #else #define SCHED_PRIO_LEVELS 16 #endif -void scheduler_init(); -void fk_schedule(); +void sched_init(); +void sched_run(); -void sched_set_status(tcb *process, unsigned int status); +void sched_set_status(tcb_t *process, unsigned int status); +void sched_switch(uint16_t current_prio, uint16_t other_prio, int in_isr); -volatile unsigned int fk_context_switch_request; +extern volatile unsigned int sched_context_switch_request; -volatile tcb *fk_threads[MAXTHREADS]; -volatile tcb *fk_thread; +extern volatile tcb_t *sched_threads[MAXTHREADS]; +extern volatile tcb_t *active_thread; extern volatile int num_tasks; -volatile int fk_pid; +extern volatile int thread_pid; //#define SCHEDSTATISTICS #if SCHEDSTATISTICS diff --git a/core/include/tcb.h b/core/include/tcb.h index 66ef085e3..9d6f5f26c 100644 --- a/core/include/tcb.h +++ b/core/include/tcb.h @@ -17,37 +17,43 @@ #define TCB_H_ #include -#include "queue.h" -#include "clist.h" +#include +#include +#include +#include /* uneven means has to be on runqueue */ -#define STATUS_NOT_FOUND 0 -#define STATUS_ON_RUNQUEUE 1 -#define STATUS_RUNNING 2 + STATUS_ON_RUNQUEUE -#define STATUS_PENDING 4 + STATUS_ON_RUNQUEUE -#define STATUS_STOPPED 8 -#define STATUS_SLEEPING 16 -#define STATUS_MUTEX_BLOCKED 32 -#define STATUS_RECEIVE_BLOCKED 64 -#define STATUS_SEND_BLOCKED 128 -#define STATUS_REPLY_BLOCKED 256 - -typedef struct tcb { +#define STATUS_NOT_FOUND (0x0000) +#define STATUS_ON_RUNQUEUE (0x0001) +#define STATUS_RUNNING (0x0002) + STATUS_ON_RUNQUEUE +#define STATUS_PENDING (0x0004) + STATUS_ON_RUNQUEUE +#define STATUS_STOPPED (0x0008) +#define STATUS_SLEEPING (0x0010) +#define STATUS_MUTEX_BLOCKED (0x0020) +#define STATUS_RECEIVE_BLOCKED (0x0040) +#define STATUS_SEND_BLOCKED (0x0080) +#define STATUS_REPLY_BLOCKED (0x0100) +#define STATUS_TIMER_WAITING (0x0200) + +typedef struct tcb_t { char* sp; - unsigned int status; + uint16_t status; uint16_t pid; uint16_t priority; + clist_node_t rq_entry; + void* wait_data; - queue_node_t msg_queue; + queue_node_t msg_waiters; - clist_node_t rq_entry; + cib_t msg_queue; + msg_t* msg_array; const char* name; char* stack_start; int stack_size; -} tcb; +} tcb_t; /** @} */ #endif /* TCB_H_ */ diff --git a/core/include/thread.h b/core/include/thread.h index 9f75470ac..77eea8d4b 100644 --- a/core/include/thread.h +++ b/core/include/thread.h @@ -14,12 +14,15 @@ */ #include +#include +/** Minimum stack size */ +#define MINIMUM_STACK_SIZE (sizeof(tcb_t)) /** * @brief Creates a new thread. - * This version will allocate it's stack itself using malloc. - * + * + * @param stack Lowest address of preallocated stack space * @param stacksize * @param flags Options: * YIELD: force context switch. @@ -32,7 +35,7 @@ * * @return returns <0 on error, pid of newly created task else. */ -int thread_create(int stacksize, char priority, int flags, void (*function) (void), const char* name); +int thread_create(char *stack, int stacksize, char priority, int flags, void (*function) (void), const char* name); /** * @brief returns the status of a process. @@ -63,9 +66,9 @@ int thread_getpid(); * @brief Measures the stack usage of a stack. * Only works if the thread was created with the flag CREATE_STACKTEST. * - * @param stack The stack you want to measure. try fk_thread->stack_start. + * @param stack The stack you want to measure. try active_thread->stack_start. */ -int fk_measure_stack_free(char* stack); +int thread_measure_stack_usage(char* stack); /* @} */ #endif /* __THREAD_H */ diff --git a/core/kernel_init.c b/core/kernel_init.c index 8c3f0a2ea..6af76399c 100644 --- a/core/kernel_init.c +++ b/core/kernel_init.c @@ -17,31 +17,30 @@ #include #include #include -#include "tcb.h" -#include "kernel.h" -#include "kernel_intern.h" -#include "scheduler.h" -#include "flags.h" -#include "cpu.h" -#include "lpm.h" -#include "thread.h" -#include "hwtimer.h" +#include +#include +#include +#include +#include +#include +#include +#include #ifdef MODULE_AUTO_INIT #include #endif #define ENABLE_DEBUG -#include "debug.h" +#include -volatile tcb *fk_threads[MAXTHREADS]; -volatile tcb *fk_thread; +volatile tcb_t *sched_threads[MAXTHREADS]; +volatile tcb_t *active_thread; volatile int lpm_prevent_sleep = 0; extern void main(void); -extern void fk_switch_context_exit(void); +extern void cpu_switch_context_exit(void); -void fk_idle(void) { +static void idle_thread(void) { while(1) { if (lpm_prevent_sleep) { lpm_set(LPM_IDLE); @@ -57,6 +56,9 @@ void fk_idle(void) { const char *main_name = "main"; const char *idle_name = "idle"; +static char main_stack[KERNEL_CONF_STACKSIZE_MAIN]; +static char idle_stack[KERNEL_CONF_STACKSIZE_IDLE]; + #ifdef MODULE_AUTO_INIT #define MAIN_FUNC auto_init #else @@ -66,20 +68,20 @@ const char *idle_name = "idle"; void kernel_init(void) { dINT(); - printf("kernel_init(): This is µkleos!\n"); + printf("kernel_init(): This is ukleos!\n"); - scheduler_init(); + sched_init(); - if (thread_create(KERNEL_CONF_STACKSIZE_IDLE, PRIORITY_IDLE, CREATE_WOUT_YIELD | CREATE_STACKTEST, fk_idle, idle_name) < 0) { + if (thread_create(idle_stack, sizeof(idle_stack), PRIORITY_IDLE, CREATE_WOUT_YIELD | CREATE_STACKTEST, idle_thread, idle_name) < 0) { printf("kernel_init(): error creating idle task.\n"); } - if (thread_create(KERNEL_CONF_STACKSIZE_MAIN, PRIORITY_MAIN, CREATE_WOUT_YIELD | CREATE_STACKTEST, MAIN_FUNC, main_name) < 0) { + if (thread_create(main_stack, sizeof(main_stack), PRIORITY_MAIN, CREATE_WOUT_YIELD | CREATE_STACKTEST, MAIN_FUNC, main_name) < 0) { printf("kernel_init(): error creating main task.\n"); } printf("kernel_init(): jumping into first task...\n"); - fk_switch_context_exit(); + cpu_switch_context_exit(); } diff --git a/core/lifo.c b/core/lifo.c new file mode 100644 index 000000000..00237caec --- /dev/null +++ b/core/lifo.c @@ -0,0 +1,44 @@ +#include + +int lifo_empty(int *array) { + return array[0] == -1; +} + +void lifo_init(int *array, int n) { + for (int i = 0; i <= n; i++) { + array[i] = -1; + } +} + +void lifo_insert(int *array, int i) { + int index = i+1; + array[index] = array[0]; + array[0] = i; +} + +int lifo_get(int *array) { + int head = array[0]; + if (head != -1) { + array[0] = array[head+1]; + } + return head; +} + + +#ifdef WITH_MAIN +#include +int main() { + int array[5]; + + lifo_init(array, 4); + + lifo_insert(array, 0); + lifo_insert(array, 1); + lifo_insert(array, 2); + lifo_insert(array, 3); + printf("get: %i\n", lifo_get(array)); + + + return 0; +} +#endif diff --git a/core/msg.c b/core/msg.c index da715d430..349caf7c5 100644 --- a/core/msg.c +++ b/core/msg.c @@ -14,80 +14,95 @@ */ #include "kernel.h" -#include "scheduler.h" +#include "sched.h" #include "msg.h" #include "queue.h" #include "tcb.h" #include #include +#include #include "flags.h" //#define ENABLE_DEBUG #include "debug.h" -int msg_send(msg* m, unsigned int target_pid, bool block) { +static int queue_msg(tcb_t *target, msg_t *m) { + int n = cib_put(&(target->msg_queue)); + + if (n != -1) { + target->msg_array[n] = *m; + return 1; + } + + return 0; +} + +int msg_send(msg_t* m, unsigned int target_pid, bool block) { if (inISR()) { return msg_send_int(m, target_pid); } - int result = 1; - - tcb *target = (tcb*)fk_threads[target_pid]; - - m->sender_pid = fk_pid; - if (m->sender_pid == target_pid) return -1; + tcb_t *target = (tcb_t*)sched_threads[target_pid]; - dINT(); + m->sender_pid = thread_pid; + if (m->sender_pid == target_pid) { + return -1; + } if (target == NULL) { - eINT(); return -1; } + dINT(); if (target->status != STATUS_RECEIVE_BLOCKED) { + if (target->msg_array && queue_msg(target, m)) { + eINT(); + return 1; + } + if (! block ) { - DEBUG("%s: receiver not waiting. block=%u\n", fk_thread->name, block); + DEBUG("%s: receiver not waiting. block=%u\n", active_thread->name, block); eINT(); return 0; } - DEBUG("%s: send_blocked.\n", fk_thread->name); + DEBUG("%s: send_blocked.\n", active_thread->name); queue_node_t n; - n.priority = fk_thread->priority; - n.data = (unsigned int) fk_thread; - DEBUG("%s: Adding node to msg_queue:\n", fk_thread->name); + n.priority = active_thread->priority; + n.data = (unsigned int) active_thread; + DEBUG("%s: Adding node to msg_waiters:\n", active_thread->name); - queue_priority_add(&(target->msg_queue), &n); + queue_priority_add(&(target->msg_waiters), &n); - fk_thread->wait_data = (void*) m; + active_thread->wait_data = (void*) m; int newstatus; - if (fk_thread->status == STATUS_REPLY_BLOCKED) { + if (active_thread->status == STATUS_REPLY_BLOCKED) { newstatus = STATUS_REPLY_BLOCKED; } else { newstatus = STATUS_SEND_BLOCKED; } - sched_set_status((tcb*)fk_thread, newstatus); + sched_set_status((tcb_t*)active_thread, newstatus); - DEBUG("%s: back from send block.\n", fk_thread->name); + DEBUG("%s: back from send block.\n", active_thread->name); } else { - DEBUG("%s: direct msg copy.\n", fk_thread->name); + DEBUG("%s: direct msg copy.\n", active_thread->name); /* copy msg to target */ - msg* target_message = (msg*)target->wait_data; + msg_t* target_message = (msg_t*)target->wait_data; *target_message = *m; sched_set_status(target, STATUS_PENDING); } eINT(); - fk_yield(); + thread_yield(); - return result; + return 1; } -int msg_send_int(msg* m, unsigned int target_pid) { - tcb *target = (tcb*)fk_threads[target_pid]; +int msg_send_int(msg_t* m, unsigned int target_pid) { + tcb_t *target = (tcb_t*)sched_threads[target_pid]; if (target->status == STATUS_RECEIVE_BLOCKED) { DEBUG("msg_send_int: direct msg copy.\n"); @@ -95,22 +110,21 @@ int msg_send_int(msg* m, unsigned int target_pid) { m->sender_pid = target_pid; /* copy msg to target */ - msg* target_message = (msg*)target->wait_data; + msg_t* target_message = (msg_t*)target->wait_data; *target_message = *m; sched_set_status(target, STATUS_PENDING); - fk_context_switch_request = 1; + sched_context_switch_request = 1; return 1; } else { DEBUG("msg_send_int: receiver not waiting.\n"); - return 0; + return (queue_msg(target, m)); } - } -int msg_send_receive(msg *m, msg *reply, unsigned int target_pid) { +int msg_send_receive(msg_t *m, msg_t *reply, unsigned int target_pid) { dINT(); - tcb *me = (tcb*) fk_threads[fk_pid]; + tcb_t *me = (tcb_t*) sched_threads[thread_pid]; sched_set_status(me, STATUS_REPLY_BLOCKED); me->wait_data = (void*) reply; msg_send(m, target_pid, true); @@ -120,66 +134,85 @@ int msg_send_receive(msg *m, msg *reply, unsigned int target_pid) { return 1; } -int msg_reply(msg *m, msg *reply) { +int msg_reply(msg_t *m, msg_t *reply) { int state = disableIRQ(); - tcb *target = (tcb*)fk_threads[m->sender_pid]; + tcb_t *target = (tcb_t*)sched_threads[m->sender_pid]; if (target->status != STATUS_REPLY_BLOCKED) { - DEBUG("%s: msg_reply(): target \"%s\" not waiting for reply.", fk_thread->name, target->name); + DEBUG("%s: msg_reply(): target \"%s\" not waiting for reply.", active_thread->name, target->name); restoreIRQ(state); return -1; } - DEBUG("%s: msg_reply(): direct msg copy.\n", fk_thread->name); + DEBUG("%s: msg_reply(): direct msg copy.\n", active_thread->name); /* copy msg to target */ - msg* target_message = (msg*)target->wait_data; + msg_t* target_message = (msg_t*)target->wait_data; *target_message = *reply; sched_set_status(target, STATUS_PENDING); restoreIRQ(state); - fk_yield(); + thread_yield(); return 1; } -int msg_reply_int(msg *m, msg *reply) { - tcb *target = (tcb*)fk_threads[m->sender_pid]; +int msg_reply_int(msg_t *m, msg_t *reply) { + tcb_t *target = (tcb_t*)sched_threads[m->sender_pid]; if (target->status != STATUS_REPLY_BLOCKED) { - DEBUG("%s: msg_reply_int(): target \"%s\" not waiting for reply.", fk_thread->name, target->name); + DEBUG("%s: msg_reply_int(): target \"%s\" not waiting for reply.", active_thread->name, target->name); return -1; } - msg* target_message = (msg*)target->wait_data; + msg_t* target_message = (msg_t*)target->wait_data; *target_message = *reply; sched_set_status(target, STATUS_PENDING); - fk_context_switch_request = 1; + sched_context_switch_request = 1; return 1; } - -int msg_receive(msg* m) { +int msg_receive(msg_t* m) { dINT(); - DEBUG("%s: msg_receive.\n", fk_thread->name); + DEBUG("%s: msg_receive.\n", active_thread->name); - tcb *me = (tcb*) fk_threads[fk_pid]; + tcb_t *me = (tcb_t*) sched_threads[thread_pid]; - me->wait_data = (void*) m; + int n = -1; + if (me->msg_array) { + n = cib_get(&(me->msg_queue)); + } - queue_node_t *n = queue_remove_head(&(me->msg_queue)); + if (n >= 0) { + DEBUG("%s: msg_receive(): We've got a queued message.\n", active_thread->name); + *m = me->msg_array[n]; + } else { + me->wait_data = (void*) m; + } - if (n == NULL) { - DEBUG("%s: msg_receive blocked\n", fk_thread->name); - sched_set_status(me, STATUS_RECEIVE_BLOCKED); + queue_node_t *node = queue_remove_head(&(me->msg_waiters)); - eINT(); - fk_yield(); + if (node == NULL) { + DEBUG("%s: msg_receive(): No thread in waiting list.\n", active_thread->name); + if (n < 0) { + DEBUG("%s: msg_receive(): No msg in queue. Going blocked.\n", active_thread->name); + sched_set_status(me, STATUS_RECEIVE_BLOCKED); - /* sender copied message */ + eINT(); + thread_yield(); + + /* sender copied message */ + } return 1; } else { - DEBUG("%s: msg_receive direct copy.\n", fk_thread->name); - tcb *sender = (tcb*)n->data; + DEBUG("%s: msg_receive(): Wakeing up waiting thread.\n", active_thread->name); + tcb_t *sender = (tcb_t*)node->data; + + if (n >= 0) { + /* we've already got a messgage from the queue. as there is a + * waiter, take it's message into the just freed queue space. + */ + m = &(me->msg_array[cib_put(&(me->msg_queue))]); + } /* copy msg */ - msg* sender_msg = (msg*)sender->wait_data; + msg_t* sender_msg = (msg_t*)sender->wait_data; *m = *sender_msg; /* remove sender from queue */ @@ -190,3 +223,15 @@ int msg_receive(msg* m) { return 1; } } + +int msg_init_queue(msg_t* array, int num) { + /* make sure brainfuck condition is met */ + if (num && (num & (num - 1)) == 0) { + tcb_t *me = (tcb_t*)active_thread; + me->msg_array = array; + cib_init(&(me->msg_queue), num); + return 0; + } + + return -1; +} diff --git a/core/mutex.c b/core/mutex.c index a9d4722ea..b31f5a44a 100644 --- a/core/mutex.c +++ b/core/mutex.c @@ -19,7 +19,8 @@ #include "queue.h" #include "tcb.h" #include "kernel.h" -#include "scheduler.h" +#include "sched.h" +#include //#define ENABLE_DEBUG #include @@ -35,92 +36,66 @@ int mutex_init(struct mutex_t* mutex) { } int mutex_trylock(struct mutex_t* mutex) { - return (atomic_set_return(&mutex->val, fk_pid ) == 0); -} - -int prio() { - return fk_thread->priority; + DEBUG("%s: trylocking to get mutex. val: %u\n", active_thread->name, mutex->val); + return atomic_set_return(&mutex->val, 1 ) == 0; } int mutex_lock(struct mutex_t* mutex) { - DEBUG("%s: trying to get mutex. val: %u\n", fk_thread->name, mutex->val); + DEBUG("%s: trying to get mutex. val: %u\n", active_thread->name, mutex->val); - if (atomic_set_return(&mutex->val,fk_pid) != 0) { + if (atomic_set_return(&mutex->val,1) != 0) { // mutex was locked. mutex_wait(mutex); } return 1; } -void mutex_unlock(struct mutex_t* mutex, int yield) { - DEBUG("%s: unlocking mutex. val: %u pid: %u\n", fk_thread->name, mutex->val, fk_pid); - int me_value; - - if (inISR()) { - me_value = 0; - yield = MUTEX_INISR; - } else { - me_value = fk_pid; - } - - if (atomic_set_return(&mutex->val,0) != me_value ) { - // there were waiters. - mutex_wake_waiters(mutex, yield); - } -} - void mutex_wait(struct mutex_t *mutex) { - dINT(); - DEBUG("%s: Mutex in use. %u\n", fk_thread->name, mutex->val); + int irqstate = disableIRQ(); + DEBUG("%s: Mutex in use. %u\n", active_thread->name, mutex->val); if (mutex->val == 0) { // somebody released the mutex. return. - mutex->val = fk_pid; - DEBUG("%s: mutex_wait early out. %u\n", fk_thread->name, mutex->val); - eINT(); + mutex->val = thread_pid; + DEBUG("%s: mutex_wait early out. %u\n", active_thread->name, mutex->val); + restoreIRQ(irqstate); return; } - sched_set_status((tcb*)fk_thread, STATUS_MUTEX_BLOCKED); + sched_set_status((tcb_t*)active_thread, STATUS_MUTEX_BLOCKED); queue_node_t n; - n.priority = (unsigned int) fk_thread->priority; - n.data = (unsigned int) fk_thread; + n.priority = (unsigned int) active_thread->priority; + n.data = (unsigned int) active_thread; n.next = NULL; - DEBUG("%s: Adding node to mutex queue: prio: %u data: %u\n", fk_thread->name, n.priority, n.data); + DEBUG("%s: Adding node to mutex queue: prio: %u\n", active_thread->name, n.priority); queue_priority_add(&(mutex->queue), &n); - eINT(); + restoreIRQ(irqstate); - fk_yield(); + thread_yield(); /* we were woken up by scheduler. waker removed us from queue. we have the mutex now. */ } -void mutex_wake_waiters(struct mutex_t *mutex, int flags) { - if ( ! (flags & MUTEX_INISR)) dINT(); - DEBUG("%s: waking up waiters.\n", fk_thread->name); - - queue_node_t *next = queue_remove_head(&(mutex->queue)); - tcb* process = (tcb*)next->data; - - sched_set_status(process, STATUS_PENDING); - - if ( mutex->queue.next != NULL) { - mutex->val = -1; - } else { - mutex->val = process->pid; +void mutex_unlock(struct mutex_t* mutex, int yield) { + DEBUG("%s: unlocking mutex. val: %u pid: %u\n", active_thread->name, mutex->val, thread_pid); + int irqstate = disableIRQ(); + + if (mutex->val != 0) { + if (mutex->queue.next) { + queue_node_t *next = queue_remove_head(&(mutex->queue)); + tcb_t* process = (tcb_t*)next->data; + DEBUG("%s: waking up waiter %s.\n", process->name); + sched_set_status(process, STATUS_PENDING); + + sched_switch(active_thread->priority, process->priority, inISR()); + } else { + mutex->val = 0; + } } - DEBUG("%s: waiters woken up.\n", fk_thread->name); - - /* If called from process, reenable interrupts, yield if requested */ - if (! (flags & MUTEX_INISR)) { - eINT(); - if (flags & MUTEX_YIELD) fk_yield(); - } else { - fk_context_switch_request = 1; - } + restoreIRQ(irqstate); } diff --git a/core/oneway_malloc.c b/core/oneway_malloc.c index 10c76c9c3..d10e23b96 100644 --- a/core/oneway_malloc.c +++ b/core/oneway_malloc.c @@ -17,6 +17,8 @@ #include #include +#include +#include #define ENABLE_DEBUG #include diff --git a/core/queue.c b/core/queue.c index edb9927f7..bfc50b4ce 100644 --- a/core/queue.c +++ b/core/queue.c @@ -56,7 +56,7 @@ void queue_priority_add(queue_node_t* root, queue_node_t* new_obj) { queue_node_t* node = root; while (node->next != NULL) { - if (node->next->priority < new_obj->priority) { + if (node->next->priority > new_obj->priority) { new_obj->next = node->next; node->next = new_obj; return; diff --git a/core/scheduler.c b/core/sched.c similarity index 50% rename from core/scheduler.c rename to core/sched.c index 279bb456a..51fdaef62 100644 --- a/core/scheduler.c +++ b/core/sched.c @@ -14,18 +14,24 @@ */ #include -#include -#include "scheduler.h" -#include "kernel.h" -#include "kernel_intern.h" -#include "clist.h" +#include +#include +#include +#include #include //#define ENABLE_DEBUG -#include "debug.h" +#include volatile int num_tasks = 0; +volatile unsigned int sched_context_switch_request; + +volatile tcb_t *sched_threads[MAXTHREADS]; +volatile tcb_t *active_thread; + +volatile int thread_pid; + clist_node_t *runqueues[SCHED_PRIO_LEVELS]; static uint32_t runqueue_bitcache = 0; @@ -33,11 +39,11 @@ static uint32_t runqueue_bitcache = 0; schedstat pidlist[MAXTHREADS]; #endif -void scheduler_init() { +void sched_init() { printf("Scheduler..."); int i; for (i=0; istatus == STATUS_RUNNING) { - my_fk_thread->status = STATUS_PENDING; + if (my_active_thread) { + if( my_active_thread->status == STATUS_RUNNING) { + my_active_thread->status = STATUS_PENDING; } #ifdef SCHED_TEST_STACK - if (*((unsigned int*)my_fk_thread->stack_start) != (unsigned int) my_fk_thread->stack_start) { - printf("scheduler(): stack overflow detected, task=%s pid=%u\n", my_fk_thread->name, my_fk_thread->pid); + if (*((unsigned int*)my_active_thread->stack_start) != (unsigned int) my_active_thread->stack_start) { + printf("scheduler(): stack overflow detected, task=%s pid=%u\n", my_active_thread->name, my_active_thread->pid); } #endif @@ -75,12 +81,12 @@ void fk_schedule() { #if SCHEDSTATISTICS extern unsigned long hwtimer_now(void); unsigned int time = hwtimer_now(); - if (my_fk_thread && (pidlist[my_fk_thread->pid].laststart)) { - pidlist[my_fk_thread->pid].runtime += time - pidlist[my_fk_thread->pid].laststart; + if (my_active_thread && (pidlist[my_active_thread->pid].laststart)) { + pidlist[my_active_thread->pid].runtime += time - pidlist[my_active_thread->pid].laststart; } #endif - DEBUG("\nscheduler: previous task: %s\n", ( my_fk_thread == NULL) ? "none" : my_fk_thread->name ); + DEBUG("\nscheduler: previous task: %s\n", ( my_active_thread == NULL) ? "none" : my_active_thread->name ); if (num_tasks == 0) { DEBUG("scheduler: no tasks left.\n"); @@ -88,44 +94,44 @@ void fk_schedule() { DEBUG("scheduler: new task created.\n"); } - my_fk_thread = NULL; - while(! my_fk_thread) { + my_active_thread = NULL; + while(! my_active_thread) { // for (int i = 0; i < SCHED_PRIO_LEVELS; i++) { /* TODO: introduce bitfield cache */ // if (runqueues[i]) { int nextrq = number_of_lowest_bit(runqueue_bitcache); clist_node_t next = *(runqueues[nextrq]); - DEBUG("scheduler: first in queue: %s\n", ((tcb*)next.data)->name); + DEBUG("scheduler: first in queue: %s\n", ((tcb_t*)next.data)->name); clist_advance(&(runqueues[nextrq])); - my_fk_thread = (tcb*)next.data; - fk_pid = (volatile int) my_fk_thread->pid; + my_active_thread = (tcb_t*)next.data; + thread_pid = (volatile int) my_active_thread->pid; #if SCHEDSTATISTICS - pidlist[my_fk_thread->pid].laststart = time; - pidlist[my_fk_thread->pid].schedules ++; + pidlist[my_active_thread->pid].laststart = time; + pidlist[my_active_thread->pid].schedules ++; #endif // break; // } // } } - DEBUG("scheduler: next task: %s\n", my_fk_thread->name); + DEBUG("scheduler: next task: %s\n", my_active_thread->name); - if (my_fk_thread != fk_thread) { - if (fk_thread != NULL) { //TODO: necessary? - if (fk_thread->status == STATUS_RUNNING) { - fk_thread->status = STATUS_PENDING ; + if (my_active_thread != active_thread) { + if (active_thread != NULL) { //TODO: necessary? + if (active_thread->status == STATUS_RUNNING) { + active_thread->status = STATUS_PENDING ; } } - sched_set_status((tcb*)my_fk_thread, STATUS_RUNNING); + sched_set_status((tcb_t*)my_active_thread, STATUS_RUNNING); } - fk_thread = (volatile tcb*) my_fk_thread; + active_thread = (volatile tcb_t*) my_active_thread; DEBUG("scheduler: done.\n"); } -void sched_set_status(tcb *process, unsigned int status) { +void sched_set_status(tcb_t *process, unsigned int status) { if (status & STATUS_ON_RUNQUEUE) { if (! (process->status & STATUS_ON_RUNQUEUE)) { DEBUG("adding process %s to runqueue %u.\n", process->name, process->priority); @@ -144,18 +150,29 @@ void sched_set_status(tcb *process, unsigned int status) { process->status = status; } -extern void fk_switch_context_exit(void); +void sched_switch(uint16_t current_prio, uint16_t other_prio, int in_isr) { + DEBUG("%s: %i %i %i\n", active_thread->name, (int)current_prio, (int)other_prio, in_isr); + if (current_prio <= other_prio) { + if (in_isr) { + sched_context_switch_request = 1; + } else { + thread_yield(); + } + } +} + +extern void cpu_switch_context_exit(void); -void fk_task_exit(void) { - DEBUG("fk_task_exit(): ending task %s...\n", fk_thread->name); +void sched_task_exit(void) { + DEBUG("sched_task_exit(): ending task %s...\n", active_thread->name); dINT(); - fk_threads[fk_thread->pid] = NULL; + sched_threads[active_thread->pid] = NULL; num_tasks--; - sched_set_status((tcb*)fk_thread, STATUS_STOPPED); + + sched_set_status((tcb_t*)active_thread, STATUS_STOPPED); - free(((tcb*)fk_thread)->stack_start); - fk_thread = NULL; - fk_switch_context_exit(); + active_thread = NULL; + cpu_switch_context_exit(); } diff --git a/core/thread.c b/core/thread.c index a9f466326..1a5bf82f7 100644 --- a/core/thread.c +++ b/core/thread.c @@ -14,7 +14,6 @@ */ #include -#include #include #include "thread.h" @@ -25,46 +24,52 @@ #include "kernel_intern.h" #include "bitarithm.h" #include "hwtimer.h" -#include "scheduler.h" +#include "sched.h" inline int thread_getpid() { - return fk_thread->pid; + return active_thread->pid; } unsigned int thread_getstatus(int pid) { - if (fk_threads[pid]==NULL) + if (sched_threads[pid]==NULL) return STATUS_NOT_FOUND; - return fk_threads[pid]->status; + return sched_threads[pid]->status; } void thread_sleep() { if ( inISR()) return; dINT(); - sched_set_status((tcb*)fk_thread, STATUS_SLEEPING); - fk_yield(); + sched_set_status((tcb_t*)active_thread, STATUS_SLEEPING); + thread_yield(); } int thread_wakeup(int pid) { + DEBUG("thread_wakeup: Trying to wakeup PID %i...\n", pid); int isr = inISR(); - if (! isr) dINT(); + if (! isr) { + DEBUG("thread_wakeup: Not in interrupt.\n"); + dINT(); + } - int result = fk_threads[pid]->status; + int result = sched_threads[pid]->status; if (result == STATUS_SLEEPING) { - sched_set_status((tcb*)fk_threads[pid], STATUS_RUNNING); + DEBUG("thread_wakeup: Thread is sleeping.\n"); + sched_set_status((tcb_t*)sched_threads[pid], STATUS_RUNNING); if (!isr) { eINT(); - fk_yield(); + thread_yield(); } else { - fk_context_switch_request = 1; + sched_context_switch_request = 1; } - return 0; + return 1; } else { + DEBUG("thread_wakeup: Thread is not sleeping!\n"); if (!isr) eINT(); return STATUS_NOT_FOUND; } } -int fk_measure_stack_free(char* stack) { +int thread_measure_stack_usage(char* stack) { unsigned int* stackp = (unsigned int*)stack; /* assumption that the comparison fails before or after end of stack */ while( *stackp == (unsigned int)stackp ) @@ -74,30 +79,26 @@ int fk_measure_stack_free(char* stack) { return space; } -int thread_create(int stacksize, char priority, int flags, void (*function) (void), const char* name) +int thread_create(char *stack, int stacksize, char priority, int flags, void (*function) (void), const char* name) { - /* stacksize must be a multitude of 4 for alignment and stacktest */ -// assert( ((stacksize & 0x03) == 0) && (stacksize > 0) ); - - // TODO: shall we autoalign the stack? - // stacksize += 4-(~(stacksize & 0x0003)); - - if (priority >= SCHED_PRIO_LEVELS) { - return -EINVAL; + /* allocate our thread control block at the top of our stackspace */ + int total_stacksize = stacksize; + stacksize -= sizeof(tcb_t); + + /* align tcb address on 32bit boundary */ + unsigned int tcb_address = (unsigned int) stack + stacksize; + if ( tcb_address & 1 ) { + tcb_address--; + stacksize--; } - - tcb *pd = (tcb*)malloc(sizeof(tcb)); - if ( pd == NULL) { - DEBUG("thread_create(): out of memory\n"); - return -ENOMEM; + if ( tcb_address & 2 ) { + tcb_address-=2; + stacksize-=2; } + tcb_t *cb = (tcb_t*) tcb_address; - char *stack = (char*)malloc(stacksize); - if (stack==NULL) - { - DEBUG("thread_create(): out of memory\n"); - free (pd); - return -ENOMEM; + if (priority >= SCHED_PRIO_LEVELS) { + return -EINVAL; } if (flags & CREATE_STACKTEST) { @@ -119,9 +120,9 @@ int thread_create(int stacksize, char priority, int flags, void (*function) (voi int pid = 0; while (pid < MAXTHREADS) { - if (fk_threads[pid] == NULL) { - fk_threads[pid] = pd; - pd->pid = pid; + if (sched_threads[pid] == NULL) { + sched_threads[pid] = cb; + cb->pid = pid; break; } pid++; @@ -130,53 +131,53 @@ int thread_create(int stacksize, char priority, int flags, void (*function) (voi if (pid == MAXTHREADS) { DEBUG("thread_create(): too many threads!\n"); - free (pd); - free (stack); - if (! inISR()) { eINT(); } return -EOVERFLOW; } - pd->sp = fk_stack_init(function,stack+stacksize); - pd->stack_start = stack; - pd->stack_size = stacksize; + cb->sp = thread_stack_init(function,stack+stacksize); + cb->stack_start = stack; + cb->stack_size = total_stacksize; + + cb->priority = priority; + cb->status = 0; - pd->priority = priority; - pd->status = 0; + cb->rq_entry.data = (unsigned int) cb; + cb->rq_entry.next = NULL; + cb->rq_entry.prev = NULL; - pd->name = name; + cb->name = name; - pd->wait_data = NULL; + cb->wait_data = NULL; - pd->msg_queue.data = 0; - pd->msg_queue.priority = 0; - pd->msg_queue.next = NULL; + cb->msg_waiters.data = 0; + cb->msg_waiters.priority = 0; + cb->msg_waiters.next = NULL; - pd->rq_entry.data = (unsigned int) pd; - pd->rq_entry.next = NULL; - pd->rq_entry.prev = NULL; + cib_init(&(cb->msg_queue),0); + cb->msg_array = NULL; num_tasks++; - DEBUG("Created thread %s. PID: %u. Priority: %u.\n", name, pd->pid, priority); + DEBUG("Created thread %s. PID: %u. Priority: %u.\n", name, cb->pid, priority); if (flags & CREATE_SLEEPING) { - sched_set_status(pd, STATUS_SLEEPING); + sched_set_status(cb, STATUS_SLEEPING); } else { - sched_set_status(pd, STATUS_PENDING); + sched_set_status(cb, STATUS_PENDING); if (!(flags & CREATE_WOUT_YIELD)) { if (! inISR()) { eINT(); - fk_yield(); + thread_yield(); } else { - fk_context_switch_request = 1; + sched_context_switch_request = 1; } } } - if (!inISR() && fk_thread!=NULL) { + if (!inISR() && active_thread!=NULL) { eINT(); } diff --git a/cpu/arm_common/Jamfile b/cpu/arm_common/Jamfile index 543888236..1889eef63 100644 --- a/cpu/arm_common/Jamfile +++ b/cpu/arm_common/Jamfile @@ -27,9 +27,14 @@ SubDir TOP cpu arm_common ; -Module arm_common : common.s bootloader.c VIC.c atomic.s arm_cpu.c ; +Module arm_common : common.s bootloader.c VIC.c atomic.s arm_cpu.c iap.c ; UseModule arm_common ; +Module profiling : profiling.c ; +if $(PROFILING) { + UseModule profiling ; +} + Module hwtimer_cpu : hwtimer_cpu.c ; Objects syscalls.c ; diff --git a/cpu/arm_common/Jamrules.arm_common b/cpu/arm_common/Jamrules.arm_common index dac4bff7d..afb14fa24 100644 --- a/cpu/arm_common/Jamrules.arm_common +++ b/cpu/arm_common/Jamrules.arm_common @@ -40,9 +40,14 @@ LINK = $(CC) ; OPTIM = -Os ; #OPTIM = -O0 -g ; + CCFLAGS += -std=gnu99 -Wall -mcpu=arm7tdmi-s -mfloat-abi=soft -mfpu=vfp ; LINKFLAGS = -mcpu=arm7tdmi-s -static -lgcc -nostartfiles -T [ FPath $(TOP) cpu $(CPU) linkerscript.x ] ; +if $(PROFILING) = 1 { + CCFLAGS += -g -finstrument-functions ; +} + AS = $(TOOLCHAIN)as ; ASFLAGS += -mcpu=arm7tdmi-s --defsym $(CPU)=1 -mfloat-abi=soft -mfpu=vfp ; diff --git a/cpu/arm_common/arm_cpu.c b/cpu/arm_common/arm_cpu.c index 35a20a47d..a5ffb50f4 100644 --- a/cpu/arm_common/arm_cpu.c +++ b/cpu/arm_common/arm_cpu.c @@ -22,10 +22,10 @@ #include #include "arm_cpu.h" -#include "scheduler.h" +#include "sched.h" #include "kernel_intern.h" -void fk_yield() { +void thread_yield() { asm("svc 0\n"); } @@ -33,7 +33,7 @@ void fk_yield() { // Processor specific routine - here for ARM7 // sizeof(void*) = sizeof(int) //---------------------------------------------------------------------------- -char * fk_stack_init(void * task_func, void * stack_start) +char * thread_stack_init(void * task_func, void * stack_start) { unsigned int * stk; stk = (unsigned int *) stack_start; @@ -42,7 +42,7 @@ char * fk_stack_init(void * task_func, void * stack_start) *stk = 0x77777777; stk--; - *stk = (unsigned int)fk_task_exit; // LR + *stk = (unsigned int)sched_task_exit; // LR stk--; *stk = (unsigned int) stack_start - 4; // SP @@ -60,12 +60,12 @@ char * fk_stack_init(void * task_func, void * stack_start) return (char*)stk; } -void fk_print_stack () { +void thread_print_stack () { register void * stack = 0; asm( "mov %0, sp" : "=r" (stack)); register unsigned int * s = (unsigned int*) stack; - printf("task: %X SP: %X\n", (unsigned int)fk_thread, (unsigned int)stack); + printf("task: %X SP: %X\n", (unsigned int)active_thread, (unsigned int)stack); register int i = 0; s += 5; while (*s != 0x77777777) { diff --git a/cpu/arm_common/atomic.s b/cpu/arm_common/atomic.s index 3bdeb94db..eb2612f0f 100644 --- a/cpu/arm_common/atomic.s +++ b/cpu/arm_common/atomic.s @@ -4,7 +4,7 @@ .code 32 .align 4 /* 0 */ -/* .extern fk_schedule*/ +/* .extern sched_run*/ /* Public functions declared in this file */ .global atomic_set_return diff --git a/cpu/arm_common/bootloader.c b/cpu/arm_common/bootloader.c index 7634c2017..f68a75e07 100644 --- a/cpu/arm_common/bootloader.c +++ b/cpu/arm_common/bootloader.c @@ -165,19 +165,21 @@ void bootloader(void) { extern void bl_init_ports(void); extern void bl_init_clks(void); extern void bl_blink(void); + extern void bl_config_init(void); /* board specific setup of clocks */ bl_init_clks(); + /* initialize bss and data */ bl_init_data(); + /* board specific setup of i/o pins */ bl_init_ports(); - /* short blinking of both of the LEDs on startup */ - bl_blink(); - /* board specific setup of UART */ + + /* UART setup */ bl_uart_init(); - printf("Board initialized.\n"); + puts("Board initialized."); } /** @} */ diff --git a/cpu/arm_common/common.s b/cpu/arm_common/common.s index cd6290530..f296f51dd 100644 --- a/cpu/arm_common/common.s +++ b/cpu/arm_common/common.s @@ -22,15 +22,14 @@ /* External references */ - .extern fk_thread - .extern fk_context_switch_request - .extern fk_schedule + .extern active_thread + .extern sched_context_switch_request + .extern sched_run .extern DEBUG_Routine /* Public functions declared in this file */ - .global fk_cpu_irq_isr - .global fk_switch_context_exit - .global fk_switch_context + .global arm_irq_handler + .global cpu_switch_context_exit .global task_return .global ctx_switch .global dINT @@ -80,32 +79,32 @@ ctx_switch2: /* store return address and spsr on user mode stack */ stmfd lr!, {r0, r1} - /* save user mode stack pointer in *fk_thread */ - ldr r1, =fk_thread /* r1 = &fk_thread */ - ldr r1, [r1] /* r1 = *r1 = fk_thread */ + /* save user mode stack pointer in *active_thread */ + ldr r1, =active_thread /* r1 = &active_thread */ + ldr r1, [r1] /* r1 = *r1 = active_thread */ str lr, [r1] /* store stack pointer in tasks tcb*/ /* now the calling task has all its registers saved on its stack and it's SP is saved in its tcb */ - /* call scheduler so fk_thread points to the next task */ - bl fk_schedule - b fk_task_return + /* call scheduler so active_thread points to the next task */ + bl sched_run + b task_return /* never coming back */ -fk_switch_context_exit: +cpu_switch_context_exit: mov r0, #NOINT|SVCMODE msr cpsr, r0 - /* call scheduler so fk_thread points to the next task */ - bl fk_schedule + /* call scheduler so active_thread points to the next task */ + bl sched_run - /* continue in fk_task_return: */ + /* continue in task_return: */ -fk_task_return: +task_return: /* load tcb->stackpointer in r0 */ - ldr r0, =fk_thread /* r0 = &fk_thread */ - ldr r0, [r0] /* r0 = *r0 = fk_thread */ + ldr r0, =active_thread /* r0 = &active_thread */ + ldr r0, [r0] /* r0 = *r0 = active_thread */ ldr r0, [r0] /* restore saved spsr and return address from tasks stack */ @@ -121,7 +120,7 @@ fk_task_return: /*---------------------------------------------------------------------------- * *----------------------------------------------------------------------------*/ -fk_cpu_irq_isr: +arm_irq_handler: sub lr, lr, #4 /* save interrupted tasks PC onto stack */ @@ -153,7 +152,7 @@ fk_cpu_irq_isr: MSR SPSR, R0 /* check if context switch was requested by irq */ - ldr r0, =fk_context_switch_request + ldr r0, =sched_context_switch_request ldr r0, [r0] cmp r0, #0x00 diff --git a/cpu/arm_common/iap.c b/cpu/arm_common/iap.c new file mode 100644 index 000000000..0f0b418ab --- /dev/null +++ b/cpu/arm_common/iap.c @@ -0,0 +1,278 @@ +/* iap driver + * + * based on iap driver for LPC2148 Controller made by Andreas Weschenfelder, 2008 + * see: + * + */ + +#include +#include +#include +#include + +//#define ENABLE_DEBUG +#include + +/* pointer to reserved flash rom section for configuration data */ +__attribute ((aligned(256))) char configmem[256] __attribute__ ((section (".configmem"))); + +static unsigned int iap_command[5]; // contains parameters for IAP command +static unsigned int iap_result[2]; // contains results +typedef void (*IAP) (unsigned int[],unsigned int[]); // typedefinition for IAP entry function +IAP IAP_Entry; + +/* some function prototypes */ +static uint32_t blank_check_sector(uint32_t tmp_sect1, uint32_t tmp_sect2); +static uint32_t prepare_sectors(uint32_t tmp_sect1, uint32_t tmp_sect2); +static uint32_t erase_sectors(uint32_t tmp_sect1, uint32_t tmp_sect2); +static uint32_t copy_ram_to_flash(uint32_t tmp_adr_dst, uint32_t tmp_adr_src, uint32_t tmp_size); +static uint32_t compare(uint32_t tmp_adr_dst, uint32_t tmp_adr_src, uint32_t tmp_size); +static uint32_t iap(uint32_t code, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4); + +/****************************************************************************** + * P U B L I C F U N C T I O N S + *****************************************************************************/ +uint8_t flashrom_write(uint8_t *dst, char *src, size_t size) { + char err; + unsigned intstate; + uint8_t sec; + + //buffer_vic = VICIntEnable; // save interrupt enable + //VICIntEnClr = 0xFFFFFFFF; // clear vic + + sec = iap_get_sector((uint32_t) dst); + if (sec == INVALID_ADDRESS) { + DEBUG("Invalid address\n"); + return 0; + } + + /* check sector */ + if(blank_check_sector(sec, sec) == SECTOR_NOT_BLANK) { + DEBUG("Warning: Sector %i not blank\n", sec); + } + + /* prepare sector */ + err = prepare_sectors(sec, sec); + if (err) { + DEBUG("\n-- ERROR: PREPARE_SECTOR_FOR_WRITE_OPERATION: %u\n", err); + /* set interrupts back and return */ +// VICIntEnable = buffer_vic; + return 0; + } + /* write flash */ + else { + intstate = disableIRQ(); + err = copy_ram_to_flash((uint32_t) dst, (uint32_t) src, 256); + restoreIRQ(intstate); + if(err) { + DEBUG("ERROR: COPY_RAM_TO_FLASH: %u\n", err); + /* set interrupts back and return */ + restoreIRQ(intstate); +// VICIntEnable = buffer_vic; + return 0; + } + /* check result */ + else { + err = compare((uint32_t) dst, (uint32_t) src, 256); + if (err) { + DEBUG("ERROR: COMPARE: %i (at position %u)\n", err, iap_result[1]); + /* set interrupts back and return */ +// VICIntEnable = buffer_vic; + return 0; + } + else + { + DEBUG("Data successfully written!\n"); + /* set interrupts back and return */ +// VICIntEnable = buffer_vic; + return 1; + } + } + } +} + + +uint8_t flashrom_erase(uint8_t *addr) { + uint8_t sec = iap_get_sector((uint32_t) addr); + unsigned intstate; + + if (sec == INVALID_ADDRESS) { + DEBUG("Invalid address\n"); + return 0; + } + + /* check sector */ + if (!blank_check_sector(sec, sec)) { + DEBUG("Sector already blank!\n"); + return 1; + } + /* prepare sector */ + if (prepare_sectors(sec, sec)) { + DEBUG("-- ERROR: PREPARE_SECTOR_FOR_WRITE_OPERATION --\n"); + return 0; + } + intstate = disableIRQ(); + /* erase sector */ + if (erase_sectors(sec, sec)) { + DEBUG("-- ERROR: ERASE SECTOR --\n"); + restoreIRQ(intstate); + return 0; + } + restoreIRQ(intstate); + /* check again */ + if (blank_check_sector(sec, sec)) { + DEBUG("-- ERROR: BLANK_CHECK_SECTOR\n"); + return 0; + } + DEBUG("Sector successfully erased.\n"); + return 1; +} + + +/****************************************************************************** + * PRIVATE FUNCTIONS + *****************************************************************************/ + +static uint32_t iap(uint32_t code, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4) { + iap_command[0] = code; // set command code + iap_command[1] = p1; // set 1st param + iap_command[2] = p2; // set 2nd param + iap_command[3] = p3; // set 3rd param + iap_command[4] = p4; // set 4th param + + ((void (*)())0x7ffffff1)(iap_command, iap_result); // IAP entry point + return *iap_result; +} + +/****************************************************************************** + * Function: blank_check_sector + * + * Description: This command is used to blank check a sector or multiple sectors + * of on-chip Flash memory. To blank check a single sector use the + * same "Start" and "End" sector numbers. + * Command: 53 + * Param0: Start Sector Number + * Param1: End Sector Number (should be greater than equal to the start + * sector number) + * + * Parameters: long tmp_sect1: Param0 + * long tmp_sect2: Param1 + * + * Return: Code CMD_SUCCESS | + * BUSY | + * SECTOR_NOT_BLANK | + * INVALID_SECTOR + * Result0: Offset of the first non blank word location if the status code is SECTOR_NOT_BLANK. + * Result1: Contents of non blank wird location. + *****************************************************************************/ +uint32_t blank_check_sector(uint32_t tmp_sect1, uint32_t tmp_sect2) { + return iap(BLANK_CHECK_SECTOR, tmp_sect1, tmp_sect2, 0 , 0); +} + + +/****************************************************************************** + * Function: copy_ram_to_flash + * + * Description: This command is used to programm the flash memory. the affected should be + * prepared first by calling "Prepare Sector for Write Operation" command. the + * affected sectors are automatically protected again once the copy command is + * successfully executed. the boot sector cannot be written by this command. + * Command: 51 + * Param0: (DST) Destination Flash adress where data bytes are to be written. + * This address should be a 512 byte boundary. + * Param1: (SRC) Source RAM adress from which data byre are to be read. + * Param2: Number of bytes to be written. Should be 512 | 1024 | 4096 | 8192. + * Param3: System Clock Frequency (CCLK) in KHz. + * + * Parameters: long tmp_adr_dst: Param0 + * long tmp_adr_src: Param1 + * long tmp_size: Param2 + * + * Return: Code CMD_SUCCESS | + * SRC_ADDR_ERROR (Address not on word boundary) | + * DST_ADDR_ERROR (Address not on correct boundary) | + * SRC_ADDR_NOT_MAPPED | + * DST_ADDR_NOT_MAPPED | + * COUNT_ERROR (Byte count is not 512 | 1024 | 4096 | 8192) | + * SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION | + * BUSY + *****************************************************************************/ +uint32_t copy_ram_to_flash(uint32_t tmp_adr_dst, uint32_t tmp_adr_src, uint32_t tmp_size) { + return iap(COPY_RAM_TO_FLASH, tmp_adr_dst, tmp_adr_src, tmp_size, _XTAL); +} + + +/****************************************************************************** + * Function: Prepare_Sector + * + * Description: This command must be executed before executing "Copy RAM to Flash" or "Erase Sector(s)" + * command. Successful execution of the "Copy RAM to Flash" or "Erase Sector(s)" command causes + * relevant sectors to be protected again. The boot sector can not be prepared by this command. To + * prepare a single sector use the same "Start" and "End" sector numbers.. + * Command code: 50 + * Param0: Start Sector Number + * Param1: End Sector Number: Should be greater than or equal to start sector number. + * + * Parameters: long tmp_sect1: Param0 + * long tmp_sect2: Param1 + * + * Return: Code CMD_SUCCESS | + * BUSY | + * INVALID_SECTOR + *****************************************************************************/ +uint32_t prepare_sectors(uint32_t tmp_sect1, uint32_t tmp_sect2) { + return iap(PREPARE_SECTOR_FOR_WRITE_OPERATION, tmp_sect1, tmp_sect2, 0 , 0); +} + + +/****************************************************************************** + * Function: erase_sectors + * + * Description: This command is used to erase a sector or multiple sectors of on-chip Flash memory. The boot + * sector can not be erased by this command. To erase a single sector use the same "Start" and "End" + * sector numbers. + * Command code: 52 + * Param0: Start Sector Number + * Param1: End Sector Number: Should be greater than or equal to start sector number. + * Param2: System Clock Frequency (CCLK) in KHz. + * + * Parameters: long tmp_sect1: Param0 + * long tmp_sect2: Param1 + * + * Return: Code CMD_SUCCESS | + * BUSY | + * SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION | + * INVALID_SECTOR + *****************************************************************************/ +uint32_t erase_sectors(uint32_t tmp_sect1, uint32_t tmp_sect2) { + return iap(ERASE_SECTOR, tmp_sect1, tmp_sect2, _XTAL, 0); +} + + +/****************************************************************************** + * Function: compare + * + * Description: This command is used to compare the memory contents at two locations. compare result may not + * be correct when source or destination address contains any of the first 64 bytes starting + * from address zero. First 64 bytes can be re-mapped to RAM. + * Command Code: 56 + * Param0(DST): Starting Flash or RAM address from where data bytes are to be + * address should be a word boundary. + * Param1(SRC): Starting Flash or RAM address from where data bytes are to be + * address should be a word boundary. + * Param2: Number of bytes to be compared. Count should be in multiple of 4. + * + * Parameters: long tmp_adr_dst + * long tmp_adr_src + * long tmp_size + * + * Return: Code CMD_SUCCESS | + * COMPARE_ERROR | + * COUNT_ERROR (Byte count is not multiple of 4) | + * ADDR_ERROR | + * ADDR_NOT_MAPPED + * Result0: Offset of the first mismatch if the Status Code is COMPARE_ERROR. + *****************************************************************************/ +uint32_t compare(uint32_t tmp_adr_dst, uint32_t tmp_adr_src, uint32_t tmp_size) { + return iap(COMPARE, tmp_adr_dst, tmp_adr_src, tmp_size, 0); +} diff --git a/cpu/arm_common/include/arm_cpu.h b/cpu/arm_common/include/arm_cpu.h index 3159c005e..6272119a6 100644 --- a/cpu/arm_common/include/arm_cpu.h +++ b/cpu/arm_common/include/arm_cpu.h @@ -11,7 +11,7 @@ extern void dINT(); extern void eINT(); -void fk_yield(); +void thread_yield(); uint32_t get_system_speed(void); void cpu_clock_scale(uint32_t source, uint32_t target, uint32_t* prescale); diff --git a/cpu/arm_common/include/iap.h b/cpu/arm_common/include/iap.h new file mode 100644 index 000000000..d2672f594 --- /dev/null +++ b/cpu/arm_common/include/iap.h @@ -0,0 +1,50 @@ +#ifndef IAP_H_ +#define IAP_H_ + +#include + +/* IAP-Commands */ +#define PREPARE_SECTOR_FOR_WRITE_OPERATION (50) +#define COPY_RAM_TO_FLASH (51) +#define ERASE_SECTOR (52) +#define BLANK_CHECK_SECTOR (53) +#define READ_PART_ID (54) +#define READ_BOOT_CODE_VERSION (55) +#define COMPARE (56) + +/* IAP status codes */ +#define CMD_SUCCESS (0) +#define INVALID_COMMAND (1) +#define SRC_ADDR_ERROR (2) +#define DST_ADDR_ERROR (3) +#define SRC_ADDR_NOT_MAPPED (4) +#define DST_ADDR_NOT_MAPPED (5) +#define COUNT_ERROR (6) +#define INVALID_SECTOR (7) +#define SECTOR_NOT_BLANK (8) +#define SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION (9) +#define COMPARE_ERROR (10) +#define BUSY (11) + +#define INVALID_ADDRESS (0xFF) + +/* IAP start location on flash */ +#define IAP_LOCATION (0x7FFFFFF1) + +/* PLL */ +#define PLLCON_PLLE (0x01) ///< PLL Enable +#define PLLCON_PLLD (0x00) ///< PLL Disable +#define PLLCON_PLLC (0x03) ///< PLL Connect +#define PLLSTAT_PLOCK (0x0400) // +#include +#include +#include + +#define MAX_TRACED_FUNCTIONS (256) +#define PROFILING_STACK_SIZE (256) + +typedef struct { + uint32_t address; + uint32_t time; + uint32_t start_time; + double consumption; + double consumption_start; + uint16_t counter; +} profiling_info_t; + +static profiling_info_t functions[MAX_TRACED_FUNCTIONS]; +static uint16_t profiling_stack[PROFILING_STACK_SIZE]; +static uint16_t profiling_sp = 0; +static uint8_t function_pending = 0; + +static uint16_t traced_functions = 0; +static uint8_t profiling = 0; + +void __attribute__((__no_instrument_function__)) profiling_init(void) { + uint16_t i; + for (i = 0; i < MAX_TRACED_FUNCTIONS; i++) { + functions[i].address = 0; + functions[i].time = 0; + functions[i].consumption = 0; + functions[i].counter = 0; + } + for (i = 0; i < PROFILING_STACK_SIZE; i++) { + profiling_stack[i] = 0; + } + + ltc4150_start(); + + profiling = 1; +} + +static int16_t __attribute__((__no_instrument_function__)) get_function_index(uint32_t addr) { + uint16_t i; + for (i = 0; i < MAX_TRACED_FUNCTIONS; i++) { + if (functions[i].address == addr) { + return i; + } + } + return -1; +} + +void __attribute__((__no_instrument_function__)) __cyg_profile_func_enter (void *func, void *caller) { + if (!profiling) { + return; + } + int16_t idx = get_function_index((uint32_t) func); + /* if function is not yet on traced */ + if ((idx < 0) && (traced_functions < MAX_TRACED_FUNCTIONS)) { + idx = traced_functions++; + functions[idx].address = (uint32_t) func; + } + /* maximu of traceable functions reached */ + else if (idx < 0) { + return; + } + + /* check if a profiled function is pending */ + if (function_pending && (profiling_stack[profiling_sp] != idx)) { + functions[idx].time += T0TC - functions[idx].start_time; + //functions[idx].consumption += ltc4150_get_intcount() - functions[idx].consumption_start; + functions[idx].consumption += ltc4150_get_total_mAh() - functions[idx].consumption_start; + } + + /* push current function on profile stack */ + profiling_sp++; + profiling_stack[profiling_sp] = idx; + + /* save stats for current function */ + functions[idx].start_time = T0TC; + functions[idx].counter++; + functions[idx].consumption_start = ltc4150_get_total_mAh(); + // functions[idx].consumption_start = ltc4150_get_intcount(); +} + +void __attribute__((__no_instrument_function__)) __cyg_profile_func_exit (void *func, void *caller) { + if (!profiling) { + return; + } + int16_t idx = get_function_index((uint32_t) func); + if (idx >= 0) { + functions[idx].time += T0TC - functions[idx].start_time; + //functions[idx].consumption += ltc4150_get_intcount() - functions[idx].consumption_start; + functions[idx].consumption += ltc4150_get_total_mAh() - functions[idx].consumption_start; + } + /* reset pending flag */ + function_pending = 0; + /* if another function is pending */ + if (profiling_sp) { + if (--profiling_sp) { + functions[profiling_stack[profiling_sp]].start_time = T0TC; + functions[profiling_stack[profiling_sp]].consumption_start = ltc4150_get_total_mAh(); + } + } +} + +void profiling_stats(void) { + uint16_t i; + for (i = 0; i < traced_functions; i++) { +// printf("Function @%04lX was running %u times for %lu ticks, consuming %li ltc-ticks\n", functions[i].address, functions[i].counter, functions[i].time, functions[i].consumption); + printf("Function @%04lX was running %u times for %lu ticks, consuming %lf mAh\n", functions[i].address, functions[i].counter, functions[i].time, functions[i].consumption); + } + puts("________________________________________________________"); +} diff --git a/cpu/arm_common/syscalls.c b/cpu/arm_common/syscalls.c index a1e583f4a..749d9bd27 100644 --- a/cpu/arm_common/syscalls.c +++ b/cpu/arm_common/syscalls.c @@ -228,7 +228,7 @@ void _exit(int n) /*---------------------------------------------------------------------------*/ int _getpid(void) { - return fk_thread->pid; + return active_thread->pid; } /*---------------------------------------------------------------------------*/ int _kill_r(struct _reent *r, int pid, int sig) @@ -237,3 +237,5 @@ int _kill_r(struct _reent *r, int pid, int sig) return -1; } /*---------------------------------------------------------------------------*/ + +void _fini(void) {} diff --git a/cpu/cc430/Jamfile b/cpu/cc430/Jamfile new file mode 100644 index 000000000..886cb4429 --- /dev/null +++ b/cpu/cc430/Jamfile @@ -0,0 +1,35 @@ +# ****************************************************************************** +# Copyright 2010, Freie Universitaet Berlin (FUB). All rights reserved. +# +# These sources were developed at the Freie Universitaet Berlin, Computer +# Systems and Telematics group (http://cst.mi.fu-berlin.de). +# ------------------------------------------------------------------------------ +# This file is part of FeuerWare. +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# FeuerWare is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see http://www.gnu.org/licenses/ . +# ------------------------------------------------------------------------------ +# For further information and questions please use the web site +# http://scatterweb.mi.fu-berlin.de +# and the mailinglist (subscription via web site) +# scatterweb@lists.spline.inf.fu-berlin.de +# ****************************************************************************** +# $Id$ + +SubDir TOP cpu cc430 ; + +Module hwtimer_cpu : hwtimer_cc430.c : hwtimer_msp430 ; +Module rtc : cc430-rtc.c ; +Module gpioint : cc430-gpioint.c ; +Module adc : cc430-adc.c : hwtimer ; + +SubInclude TOP cpu msp430-common ; diff --git a/cpu/cc430/Jamrules.cc430 b/cpu/cc430/Jamrules.cc430 new file mode 100644 index 000000000..c66536fc9 --- /dev/null +++ b/cpu/cc430/Jamrules.cc430 @@ -0,0 +1 @@ +include [ FPath $(TOP) cpu msp430-common Jamrules.msp430-common ] ; diff --git a/cpu/cc430/cc430-adc.c b/cpu/cc430/cc430-adc.c new file mode 100644 index 000000000..3617d155c --- /dev/null +++ b/cpu/cc430/cc430-adc.c @@ -0,0 +1,147 @@ +/* ************************************************************************************************* + * + * 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. + * + * ************************************************************************************************* + * ADC12 functions. + * ************************************************************************************************/ + + +#include +#include +#include +#include + +uint16_t adc12_result; +uint8_t adc12_data_ready; + +/* ************************************************************************************************* + * @fn adc12_single_conversion + * @brief Init ADC12. Do single conversion. Turn off ADC12. + * @param none + * @return none + * ************************************************************************************************/ +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 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 */ + eINT(); + + /* Wait 2 ticks (66us) to allow internal reference to settle */ + hwtimer_wait(2); + + /* Start ADC12 */ + ADC12CTL0 |= ADC12ENC; + + /* Clear data ready flag */ + adc12_data_ready = 0; + + /* Sampling and conversion start */ + ADC12CTL0 |= ADC12SC; + + /* Wait until ADC12 has finished */ + hwtimer_wait(5); + while (!adc12_data_ready); + + /* Shut down ADC12 */ + ADC12CTL0 &= ~(ADC12ENC | ADC12SC | sht); + ADC12CTL0 &= ~ADC12ON; + + /* Shut down reference voltage */ + REFCTL0 &= ~(REFMSTR + ref + REFON); + + ADC12IE = 0; + + /* Return ADC result */ + return adc12_result; +} + +/* ************************************************************************************************* + * @fn ADC12ISR + * @brief Store ADC12 conversion result. Set flag to indicate data ready. + * @param none + * @return none + * ************************************************************************************************/ +interrupt (ADC12_VECTOR) __attribute__ ((naked)) adc_isr (void) { + __enter_isr(); + switch(ADC12IV) { + case 0: + break; /* Vector 0: No interrupt */ + case 2: + break; /* Vector 2: ADC 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; + break; + case 8: + break; /* Vector 8: ADC12IFG1 */ + case 10: + break; /* Vector 10: ADC12IFG2 */ + case 12: + break; /* Vector 12: ADC12IFG3 */ + case 14: + break; /* Vector 14: ADC12IFG4 */ + case 16: + break; /* Vector 16: ADC12IFG5 */ + case 18: + break; /* Vector 18: ADC12IFG6 */ + case 20: + break; /* Vector 20: ADC12IFG7 */ + case 22: + break; /* Vector 22: ADC12IFG8 */ + case 24: + break; /* Vector 24: ADC12IFG9 */ + case 26: + break; /* Vector 26: ADC12IFG10 */ + case 28: + break; /* Vector 28: ADC12IFG11 */ + case 30: + break; /* Vector 30: ADC12IFG12 */ + case 32: + break; /* Vector 32: ADC12IFG13 */ + case 34: + break; /* Vector 34: ADC12IFG14 */ + default: + break; + } + __exit_isr(); +} + + diff --git a/cpu/cc430/cc430-gpioint.c b/cpu/cc430/cc430-gpioint.c new file mode 100644 index 000000000..460d2a487 --- /dev/null +++ b/cpu/cc430/cc430-gpioint.c @@ -0,0 +1,231 @@ +/****************************************************************************** +Copyright 2010, Freie Universität Berlin (FUB). All rights reserved. + +These sources were developed at the Freie Universitaet Berlin, Computer Systems +and Telematics group (http://cst.mi.fu-berlin.de). +------------------------------------------------------------------------------- +This file is part of µkleos. + +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +FeuerWare is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see http://www.gnu.org/licenses/ . +-------------------------------------------------------------------------------- +For further information and questions please use the web site + http://scatterweb.mi.fu-berlin.de +and the mailinglist (subscription via web site) + scatterweb@lists.spline.inf.fu-berlin.de +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** min and max portnumber to generate interrupts */ +#define PORTINT_MIN (1) +#define PORTINT_MAX (2) + +/** amount of interrupt capable ports */ +#define INT_PORTS (2) + +/** number of bits per port */ +#define BITMASK_SIZE (8) + +/** debouncing port interrupts */ +#define DEBOUNCE_TIMEOUT (250) + +/** interrupt callbacks */ +fp_irqcb cb[INT_PORTS][BITMASK_SIZE]; + +/** debounce interrupt flags */ +uint8_t debounce_flags[INT_PORTS]; + +/** debounce interrupt times */ +uint16_t debounce_time[INT_PORTS][BITMASK_SIZE]; + +uint16_t c1 = 0, c2 = 0; + +void gpioint_init(void) { + uint8_t i, j; + for (i = 0; i < INT_PORTS; i++) { + for (j = 0; j < BITMASK_SIZE; j++) { + cb[i][j] = NULL; + debounce_time[i][j] = 0; + } + } +} + +bool gpioint_set(int port, uint32_t bitmask, int flags, fp_irqcb callback) { + int8_t base; + + if ((port >= PORTINT_MIN) && (port <= PORTINT_MAX)) { + /* set the callback function */ + base = number_of_highest_bit(bitmask); + if (base >= 0) { + cb[port - PORTINT_MIN][base] = callback; + } + else { + return false; + } + if (flags & GPIOINT_DEBOUNCE) { + debounce_flags[port - PORTINT_MIN] |= bitmask; + } + else { + debounce_flags[port - PORTINT_MIN] &= ~bitmask; + } + } + + switch (port) { + case 1: + /* set port to input */ + P1DIR &= ~bitmask; + /* enable internal pull-down */ + P1OUT &= ~bitmask; + P1REN |= bitmask; + + /* reset IRQ flag */ + P1IFG &= ~bitmask; + + /* trigger on rising... */ + if (flags & GPIOINT_RISING_EDGE) { + P1IES &= bitmask; + } + /* ...or falling edge */ + if (flags & GPIOINT_FALLING_EDGE) { + P1IES |= bitmask; + } + + /* disable interrupt */ + if (flags == GPIOINT_DISABLE) { + P1IE &= ~bitmask; + } + /* enable interrupt */ + P1IE |= bitmask; + break; + case 2: + /* set port to input */ + P2DIR &= ~bitmask; + /* enable internal pull-down */ + P2OUT &= ~bitmask; + P2REN |= bitmask; + + /* reset IRQ flag */ + P2IFG &= ~bitmask; + + /* trigger on rising... */ + if (flags == GPIOINT_RISING_EDGE) { + P2IES &= bitmask; + } + /* ...or falling edge */ + else if (flags == GPIOINT_FALLING_EDGE) { + P2IES |= bitmask; + } + /* or disable interrupt */ + else { + P2IE &= ~bitmask; + } + /* enable interrupt */ + P2IE |= bitmask; + break; + default: + return false; + } + return 1; +} + +interrupt (PORT1_VECTOR) __attribute__ ((naked)) port1_isr(void) { + uint8_t int_enable, ifg_num, p1ifg; + uint16_t p1iv; + uint16_t diff; + __enter_isr(); + + /* Debounce + * Disable PORT1 IRQ + */ + p1ifg = P1IFG; + p1iv = P1IV; + int_enable = P1IE; + P1IE = 0x00; + + ifg_num = (p1iv >> 1) - 1; + /* check interrupt source */ + if (debounce_flags[0] & p1ifg) { + /* check if bouncing */ + diff = hwtimer_now() - debounce_time[0][ifg_num]; + if (diff > DEBOUNCE_TIMEOUT) { + debounce_time[0][ifg_num] = hwtimer_now(); + if (cb[0][ifg_num] != NULL) { + cb[0][ifg_num](); + } + } + else { + /* TODO: check for long duration irq */ + asm volatile (" nop "); + } + } + else { + if (cb[0][ifg_num] != NULL) { + cb[0][ifg_num](); + } + } + + P1IFG = 0x00; + P1IE = int_enable; + __exit_isr(); +} + +interrupt (PORT2_VECTOR) __attribute__ ((naked)) port2_isr(void) { + uint8_t int_enable, ifg_num, p2ifg; + uint16_t p2iv; + uint16_t diff; + __enter_isr(); + + /* Debounce + * Disable PORT2 IRQ + */ + p2ifg = P2IFG; + p2iv = P2IV; + int_enable = P2IE; + P2IE = 0x00; + + ifg_num = (p2iv >> 1) - 1; + /* check interrupt source */ + if (debounce_flags[1] & p2ifg) { + /* check if bouncing */ + diff = hwtimer_now() - debounce_time[1][ifg_num]; + if (diff > DEBOUNCE_TIMEOUT) { + debounce_time[1][ifg_num] = hwtimer_now(); + c1++; + if (cb[1][ifg_num] != NULL) { + cb[1][ifg_num](); + } + } + else { + c2++; + /* TODO: check for long duration irq */ + asm volatile (" nop "); + } + } + else { + if (cb[1][ifg_num] != NULL) { + cb[1][ifg_num](); + } + } + + P2IFG = 0x00; + P2IE = int_enable; + __exit_isr(); +} + diff --git a/cpu/cc430/cc430-rtc.c b/cpu/cc430/cc430-rtc.c new file mode 100644 index 000000000..8d2b43fcb --- /dev/null +++ b/cpu/cc430/cc430-rtc.c @@ -0,0 +1,201 @@ +/****************************************************************************** +Copyright 2010, Freie Universitaet Berlin (FUB). All rights reserved. + +These sources were developed at the Freie Universitaet Berlin, Computer Systems +and Telematics group (http://cst.mi.fu-berlin.de). +------------------------------------------------------------------------------- +This file is part of µkleos. + +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +FeuerWare is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see http://www.gnu.org/licenses/ . +-------------------------------------------------------------------------------- +For further information and questions please use the web site + http://scatterweb.mi.fu-berlin.de +and the mailinglist (subscription via web site) + scatterweb@lists.spline.inf.fu-berlin.de +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include + +//static volatile time_t epoch; +static struct tm time_to_set; +static int set_time = 0; +int rtc_second_pid = 0; + +/*---------------------------------------------------------------------------*/ +void rtc_init(void) { + /* Set to calendar mode */ + RTCCTL1 |= RTCMODE_H; + + /* enable ready interrupt (every second) */ +#ifndef ENABLE_DEBUG + RTCCTL0 |= RTCRDYIE; +#endif +} + +/*---------------------------------------------------------------------------*/ +void rtc_enable(void) { + /* Set RTC operational */ + RTCCTL1 &= ~RTCHOLD_H; +} +/*---------------------------------------------------------------------------*/ +void rtc_disable(void) { + /* Stop RTC */ + RTCCTL1 |= RTCHOLD_H; +} +/*---------------------------------------------------------------------------*/ +void rtc_set_localtime(struct tm* localt) { + if(localt == NULL) { + return; + } + + /* copy time to be set */ + memcpy(&time_to_set, localt, sizeof(struct tm)); + /* set interrupt to set this time after the next transition */ +// RTCCTL0 |= RTCRDYIE; + set_time = 1; +} + +/*--------------------------------------------------------------------------- +void rtc_set(time_t time) { + struct tm* localt; + localt = localtime(&time); // convert seconds to broken-down time + rtc_set_localtime(localt); + epoch = time - localt->tm_sec - localt->tm_min * 60; +} +*/ + +/*--------------------------------------------------------------------------- +time_t rtc_time(void) { + time_t sec; + struct tm t; + rtc_get_localtime(&t); + sec = mktime(&t); + return sec; +} +*/ +/*---------------------------------------------------------------------------*/ +void rtc_get_localtime(struct tm* localt) { + uint8_t success = 0; + uint8_t i; + uint16_t tmpyear; + + if( localt == NULL ) { + return; + } + + while (!success) { + for (i = 0; i < 8; i++) { + /* try again when RTC is in transition */ + if (!(RTCCTL1 & RTCRDY_H)) { + break; + } + switch (i) { + case 0: + localt->tm_sec = RTCSEC; + break; + case 1: + localt->tm_min = RTCMIN; + break; + case 2: + localt->tm_hour = RTCHOUR; + break; + case 3: + localt->tm_mday = RTCDAY; + break; + case 4: + localt->tm_wday = RTCDOW; + break; + case 5: + localt->tm_mon = RTCMON - 1; + break; + case 6: + tmpyear = RTCYEARL; + tmpyear |= (RTCYEARH << 0x08); + localt->tm_year = tmpyear - 1900; + break; + default: + success = 1; + break; + } + } + } +} + +/*---------------------------------------------------------------------------*/ +void rtc_set_alarm(struct tm* localt, rtc_alarm_mask_t mask) { + if (mask & RTC_ALARM_MIN) { + RTCAMIN = localt->tm_min; + RTCAMIN |= BIT7; + } + if (mask & RTC_ALARM_HOUR) { + RTCAHOUR = localt->tm_hour; + RTCAHOUR |= BIT7; + } + if (mask & RTC_ALARM_DOW) { + RTCADOW = localt->tm_wday; + RTCADOW |= BIT7; + } + if (mask & RTC_ALARM_DOM) { + RTCADAY = localt->tm_mday; + RTCADAY |= BIT7; + } + RTCCTL0 |= RTCAIE; +} + +/*---------------------------------------------------------------------------*/ +void rtc_remove_alarm(void) { + /* reset all AE bits */ + RTCAHOUR &= ~BIT7; + RTCAMIN &= ~BIT7; + RTCADAY &= ~BIT7; + RTCADOW &= ~BIT7; + + /* reset alarm interrupt enable */ + RTCCTL0 &= ~RTCAIE; +} +/*---------------------------------------------------------------------------*/ +interrupt(RTC_VECTOR) __attribute__ ((naked)) rtc_isr(void) { + __enter_isr(); + /* RTC is save to write for up to one second now */ + if (RTCIV == RTC_RTCRDYIFG) { + /* disable interrupt */ + //RTCCTL0 &= ~RTCRDYIE; + + if (set_time) { + set_time = 0; + /* set previous set time and reset it */ + RTCSEC = time_to_set.tm_sec; + RTCMIN = time_to_set.tm_min; + RTCHOUR = time_to_set.tm_hour; + RTCDAY = time_to_set.tm_mday; + RTCDOW = time_to_set.tm_wday; + RTCMON = time_to_set.tm_mon + 1; + RTCYEARL = (time_to_set.tm_year + 1900) & 0xFF; + RTCYEARH = (time_to_set.tm_year + 1900) >> 0x08; + } + if (rtc_second_pid) { + msg_t m; + m.type = RTC_SECOND; + msg_send_int(&m, rtc_second_pid); + } + } + /* RTC alarm */ + else if (RTCIV == RTC_RTCAIFG) { + } + __exit_isr(); +} diff --git a/cpu/cc430/hwtimer_cc430.c b/cpu/cc430/hwtimer_cc430.c new file mode 100644 index 000000000..64a7a9bb0 --- /dev/null +++ b/cpu/cc430/hwtimer_cc430.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include + +// #define ENABLE_DEBUG (1) +#include + +static uint32_t ticks = 0; + +extern void (*int_handler)(int); +extern void TA0_unset(short timer); + +void timerA_init() +{ + ticks = 0; // Set tick counter value to 0 + TA0CTL = TASSEL_1 + TACLR; // Clear the timer counter, set ACLK + TA0CTL &= ~TAIE; // Clear the IFG + + volatile unsigned int *ccr = &TA0CCR0; + volatile unsigned int *ctl = &TA0CCTL0; + + for (int i = 0; i < ARCH_MAXTIMERS; i++) { + *(ccr+i) = 0; + *(ctl+i) &= ~(CCIFG); + *(ctl+i) &= ~(CCIE); + } + + TA0CTL |= MC_2; +} + +interrupt(TIMER0_A0_VECTOR) __attribute__ ((naked)) timer0_a0_isr(void) { + __enter_isr(); + + TA0_unset(0); + int_handler(0); + __exit_isr(); +} + +interrupt(TIMER0_A1_VECTOR) __attribute__ ((naked)) timer0_a1_5_isr(void) { + __enter_isr(); + + short taiv = TA0IV; + short timer; + + if (taiv & TAIFG) { + DEBUG("Overflow\n"); + } + else { + timer = (taiv/2); + TA0_unset(timer); + int_handler(timer); + } + + __exit_isr(); +} diff --git a/cpu/cc430/include/cc430-adc.h b/cpu/cc430/include/cc430-adc.h new file mode 100644 index 000000000..8ac19a938 --- /dev/null +++ b/cpu/cc430/include/cc430-adc.h @@ -0,0 +1,44 @@ +/* ************************************************************************************************* + * + * 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 CC430_ADC_H +#define CC430_ADC_H + +extern uint16_t adc12_single_conversion(uint16_t ref, uint16_t sht, uint16_t channel); + +extern uint16_t adc12_result; +extern uint8_t adc12_data_ready; + +#endif diff --git a/cpu/cc430/include/cc430-rtc.h b/cpu/cc430/include/cc430-rtc.h new file mode 100644 index 000000000..15e27bdb4 --- /dev/null +++ b/cpu/cc430/include/cc430-rtc.h @@ -0,0 +1,75 @@ +/****************************************************************************** +Copyright 2010, Freie Universitaet Berlin (FUB). All rights reserved. + +These sources were developed at the Freie Universitaet Berlin, Computer Systems +and Telematics group (http://cst.mi.fu-berlin.de). +------------------------------------------------------------------------------- +This file is part of µkleos. + +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +FeuerWare is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see http://www.gnu.org/licenses/ . +-------------------------------------------------------------------------------- +For further information and questions please use the web site + http://scatterweb.mi.fu-berlin.de +and the mailinglist (subscription via web site) + scatterweb@lists.spline.inf.fu-berlin.de +*******************************************************************************/ + +#ifndef CC430_RTC_H +#define CC430_RTC_H +#include +#include + +/** + * @defgroup cc430_rtc CC430 Real Time Clock + * @ingroup cc430 + */ + +/** + * @file cc430-rtc.h + * @brief CC430 Real Time Clock + * + * @author Freie Universität Berlin, Computer Systems & Telematics, µkleos + * @version $Revision $ + */ + +/** + * @brief Mask for RTC alarms + * @see ::rtc_set_alarm + */ +typedef enum { + RTC_ALARM_DISABLED = 0x00, ///< Alarm disables + RTC_ALARM_MIN = 0x01, ///< Alarm mask for Minutes + RTC_ALARM_HOUR = 0x02, ///< Alarm mask for Hours + RTC_ALARM_DOW = 0x04, ///< Alarm mask for Day of Week + RTC_ALARM_DOM = 0x08 ///< Alarm mask for Day of Month +} rtc_alarm_mask_t; + +/** + * @brief Sets the alarm + * @internal + * @param[in] localt Alarm time + * @param[in] mask Sets the registers to poll for the alarm + * + * To disable the alarm set mask to RTC_ALARM_DISABLED. + * + * @see ::rtc_alarm_mask + */ +void rtc_set_alarm(struct tm* localti, rtc_alarm_mask_t mask); + +/** + * @brief Resets any set alarm + */ +void rtc_remove_alarm(void); + + +#endif diff --git a/cpu/lpc214x/startup.s b/cpu/lpc214x/startup.s index f9b1f6900..8a0c95b88 100644 --- a/cpu/lpc214x/startup.s +++ b/cpu/lpc214x/startup.s @@ -55,7 +55,7 @@ Undef_Addr: .word UNDEF_Routine /* defined in main.c */ SWI_Addr: .word ctx_switch /* defined in main.c */ PAbt_Addr: .word UNDEF_Routine /* defined in main.c */ DAbt_Addr: .word UNDEF_Routine /* defined in main.c */ -IRQ_Addr: .word fk_cpu_irq_isr /* defined in main.c */ +IRQ_Addr: .word arm_irq_handler /* defined in main.c */ FIQ_Addr: .word FIQ_Routine /* defined in main.c */ .word 0 /* rounds the vectors and ISR addresses to 64 bytes total */ diff --git a/cpu/lpc2387/Jamfile b/cpu/lpc2387/Jamfile index 6b5fb58ed..bacd10a74 100644 --- a/cpu/lpc2387/Jamfile +++ b/cpu/lpc2387/Jamfile @@ -32,6 +32,8 @@ UseModule cpu ; Module rtc : lpc2387-rtc.c ; Module gpioint : lpc2387-gpioint.c ; +Module adc : lpc2387-adc.c ; +Module mci : lpc2387-mci.c asmfunc.s ; Objects startup.s ; diff --git a/cpu/lpc2387/asmfunc.s b/cpu/lpc2387/asmfunc.s new file mode 100644 index 000000000..4bdb45468 --- /dev/null +++ b/cpu/lpc2387/asmfunc.s @@ -0,0 +1,96 @@ +@-----------------------------------------------------------@ +@ Fast Block Copy (declared in diskio.h) +@-----------------------------------------------------------@ + +.global Copy_un2al +.arm +Copy_un2al: + STMFD SP!, {R4-R8} + ANDS IP, R1, #3 + BEQ lb_align + + BIC R1, #3 + MOV IP, IP, LSL #3 + RSB R8, IP, #32 + LDMIA R1!, {R7} +lb_l1: MOV R3, R7 + LDMIA R1!, {R4-R7} + MOV R3, R3, LSR IP + ORR R3, R3, R4, LSL R8 + MOV R4, R4, LSR IP + ORR R4, R4, R5, LSL R8 + MOV R5, R5, LSR IP + ORR R5, R5, R6, LSL R8 + MOV R6, R6, LSR IP + ORR R6, R6, R7, LSL R8 + SUBS R2, R2, #16 + STMIA R0!, {R3-R6} + BNE lb_l1 + LDMFD SP!, {R4-R8} + BX LR + +lb_align: + LDMIA R1!, {R3-R6} + SUBS R2, R2, #16 + STMIA R0!, {R3-R6} + BNE lb_align + LDMFD SP!, {R4-R8} + BX LR + + +.global Copy_al2un +.arm +Copy_al2un: + STMFD SP!, {R4-R8} + ANDS IP, R0, #3 + BEQ sb_align + + MOV IP, IP, LSL #3 + RSB R8, IP, #32 + + LDMIA R1!, {R4-R7} +sb_p1: STRB R4, [R0], #1 + MOV R4, R4, LSR #8 + TST R0, #3 + BNE sb_p1 + ORR R4, R4, R5, LSL IP + MOV R5, R5, LSR R8 + ORR R5, R5, R6, LSL IP + MOV R6, R6, LSR R8 + ORR R6, R6, R7, LSL IP + SUBS R2, R2, #16 + STMIA R0!, {R4-R6} + +sb_l1: MOV R3, R7 + LDMIA R1!, {R4-R7} + MOV R3, R3, LSR R8 + ORR R3, R3, R4, LSL IP + MOV R4, R4, LSR R8 + ORR R4, R4, R5, LSL IP + MOV R5, R5, LSR R8 + ORR R5, R5, R6, LSL IP + MOV R6, R6, LSR R8 + ORR R6, R6, R7, LSL IP + SUBS R2, R2, #16 + STMIA R0!, {R3-R6} + BNE sb_l1 + + MOV R7, R7, LSR R8 +sb_p2: SUBS IP, IP, #8 + STRB R7, [R0], #1 + MOV R7, R7, LSR #8 + BNE sb_p2 + + LDMFD SP!, {R4-R8} + BX LR + +sb_align: + LDMIA R1!, {R3-R6} + SUBS R2, #16 + STMIA R0!, {R3-R6} + BNE sb_align + LDMFD SP!, {R4-R8} + BX LR + +.end + diff --git a/cpu/lpc2387/include/cpu-conf.h b/cpu/lpc2387/include/cpu-conf.h index dd0a216d0..9e6a2dde9 100644 --- a/cpu/lpc2387/include/cpu-conf.h +++ b/cpu/lpc2387/include/cpu-conf.h @@ -68,7 +68,7 @@ and the mailinglist (subscription via web site) * @{ */ #ifndef KERNEL_CONF_STACKSIZE_DEFAULT -#define KERNEL_CONF_STACKSIZE_DEFAULT 2500 +#define KERNEL_CONF_STACKSIZE_DEFAULT 4500 #endif #define KERNEL_CONF_STACKSIZE_IDLE 500 @@ -84,5 +84,8 @@ and the mailinglist (subscription via web site) #define CC_CONF_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) /** @} */ +#define TRANSCEIVER_BUFFER_SIZE (10) +#define RX_BUF_SIZE (10) + /** @} */ #endif /* CPUCONF_H_ */ diff --git a/cpu/lpc2387/include/lpc2387-rtc.h b/cpu/lpc2387/include/lpc2387-rtc.h index f8de46c06..080a330cf 100644 --- a/cpu/lpc2387/include/lpc2387-rtc.h +++ b/cpu/lpc2387/include/lpc2387-rtc.h @@ -24,8 +24,8 @@ and the mailinglist (subscription via web site) scatterweb@lists.spline.inf.fu-berlin.de *******************************************************************************/ -#ifndef __RTC_H -#define __RTC_H +#ifndef LPC2387_RTC_H +#define LPC2387_RTC_H /** * @defgroup lpc2387_rtc LPC2387 Real-Time-Clock @@ -48,6 +48,7 @@ and the mailinglist (subscription via web site) * @note $Id: lpc2387-rtc.h 1998 2010-03-16 13:05:41Z baar $ */ +#include #include #include #include "lpc2387.h" @@ -76,14 +77,7 @@ enum rtc_alarm_mask { RTC_AMR_YEAR= AMRYEAR, ///< Alarm mask for Year }; -/** - * @brief Initializes the RTC - * @internal - * During reboots only alarms are reset. - */ -void rtc_init(void); - -void _rtc_reset(void); +void rtc_reset(void); /** * @brief Returns the time of compilation in seconds @@ -105,22 +99,6 @@ time_t rtc_time(struct timeval* time); */ void rtc_set(time_t time); -/** - * @brief Enables the RTC - */ -void rtc_enable(void); - -/** - * @brief Disables the RTC - */ -void rtc_disable(void); - -/** - * @brief Returns the current time in broken down format directly from the RTC - * @param[out] localt Pointer to structure to receive time - */ -void rtc_get_localtime(struct tm* localt); - /** * @brief Sets the alarm * @internal @@ -131,7 +109,7 @@ void rtc_get_localtime(struct tm* localt); * * @see ::rtc_alarm_mask */ -void _rtc_set_alarm(struct tm* localt, enum rtc_alarm_mask mask); +void rtc_set_alarm(struct tm* localt, enum rtc_alarm_mask mask); /** * @brief Gets the current alarm setting diff --git a/cpu/lpc2387/include/lpc2387.h b/cpu/lpc2387/include/lpc2387.h index d70853a77..27bcb69b4 100644 --- a/cpu/lpc2387/include/lpc2387.h +++ b/cpu/lpc2387/include/lpc2387.h @@ -9,8 +9,8 @@ #ifndef __LPC2387_H #define __LPC2387_H -#include "lpc23xx.h" -#include "bitarithm.h" +#include +#include #define F_CCO 288000000 #define CL_CPU_DIV 4 ///< CPU clock divider @@ -23,6 +23,8 @@ #define GPIO_INT 17 #define IRQP_GPIO 4 +#define _XTAL (72000) + /** * @name Timer Symbols * @{ diff --git a/cpu/lpc2387/linkerscript.x b/cpu/lpc2387/linkerscript.x index 704829893..eaf2a69dc 100644 --- a/cpu/lpc2387/linkerscript.x +++ b/cpu/lpc2387/linkerscript.x @@ -1,194 +1,231 @@ -/****************************************************************************** -Copyright 2008-2009, Freie Universitaet Berlin (FUB). All rights reserved. - -These sources were developed at the Freie Universitaet Berlin, Computer Systems -and Telematics group (http://cst.mi.fu-berlin.de). -------------------------------------------------------------------------------- -This file is part of FeuerWare. - -This program is free software: you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation, either version 3 of the License, or (at your option) any later -version. - -FeuerWare is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program. If not, see http://www.gnu.org/licenses/ . --------------------------------------------------------------------------------- -For further information and questions please use the web site - http://scatterweb.mi.fu-berlin.de -and the mailinglist (subscription via web site) - scatterweb@lists.spline.inf.fu-berlin.de -*******************************************************************************/ - -/* specify the LPC2387 memory areas (see LPC2387 datasheet page 15) */ -MEMORY -{ - flash : ORIGIN = 0, LENGTH = 512K /* FLASH ROM */ - ram_battery : ORIGIN = 0xE0084000, LENGTH = 2K /* Battery RAM */ - ram : ORIGIN = 0x40000000, LENGTH = 64K /* LOCAL ON-CHIP STATIC RAM */ - ram_usb : ORIGIN = 0x7FD00000, LENGTH = 16K /* USB RAM */ - ram_ethernet : ORIGIN = 0x7FE00000, LENGTH = 16K /* ethernet RAM */ -} - -__stack_und_size = 4; /* stack for "undefined instruction" interrupts */ -__stack_abt_size = 4; /* stack for "abort" interrupts */ -__stack_fiq_size = 64; /* stack for "FIQ" interrupts */ -__stack_irq_size = 400; /* stack for "IRQ" normal interrupts */ -__stack_svc_size = 400; /* stack for "SVC" supervisor mode */ -__stack_usr_size = 4096; /* stack for user operation (kernel init) */ -__stack_size = __stack_und_size + __stack_abt_size + __stack_fiq_size + __stack_irq_size + __stack_svc_size + __stack_usr_size; - -/* now define the output sections */ -SECTIONS -{ - .text : /* collect all sections that should go into FLASH after startup */ - { - *(.vectors) /* Exception Vectors and branch table >= 64 bytes */ - . = ALIGN(64); - *(.init) - *(.init0) /* Start here after reset. */ - *(.init1) - *(.init2) /* Copy data loop */ - *(.init3) - *(.init4) /* Clear bss */ - *(.init5) - *(.init6) /* C++ constructors. */ - *(.init7) - *(.init8) - *(.init9) /* Call main(). */ - - *(.text) /* all .text sections (code) */ - *(.text.*) - *(.gnu.linkonce.t.*) - - . = ALIGN(4); - __commands_start = .; - *(.commands) /* command table */ - __commands_end = .; - . = ALIGN(4); - __cfgspec_start = .; - *(.cfgspec) /* configuration spec table */ - __cfgspec_end = .; - . = ALIGN(4); - - *(.rodata .rodata.*) /* all .rodata sections (constants, strings, etc.) */ - *(.gnu.linkonce.r.*) - *(.glue_7) /* all .glue_7 sections (no idea what these are) */ - *(.glue_7t) /* all .glue_7t sections (no idea what these are) */ - - *(.fini9) - *(.fini8) - *(.fini7) - *(.fini6) /* C++ destructors. */ - *(.fini5) - *(.fini4) - *(.fini3) - *(.fini2) - *(.fini1) - *(.fini0) /* Infinite loop after program termination. */ - *(.fini) - - *(.gcc_except_table) - - } >flash /* put all the above into FLASH */ - . = ALIGN(4); - _etext = . ; /* define a global symbol _etext just after the last code byte */ - - /************************************************************************** - * RAM - **************************************************************************/ - - /* - * collect all uninitialized sections that go into RAM - */ - .noinit (NOLOAD) : - { - __noinit_start = .; - PROVIDE(__fiq_handler = .); - *(.fiq) - *(.noinit) - } > ram - . = ALIGN(4); - __noinit_end = .; - - /* - * collect all zero initialized sections that go into RAM - */ - .bss (NOLOAD) : - { - . = ALIGN(4); /* ensure data is aligned so relocation can use 4-byte operations */ - __bss_start = .; /* define a global symbol marking the start of the .bss section */ - *(.bss) /* all .bss sections */ - *(COMMON) - } > ram /* put all the above in RAM (it will be cleared in the startup code */ - . = ALIGN(4); /* ensure data is aligned so relocation can use 4-byte operations */ - __bss_end = . ; /* define a global symbol marking the end of the .bss section */ - - /* - * collect all initialized .data sections that go into RAM - * initial values get placed at the end of .text in flash - */ - .data : AT (_etext) - { - . = ALIGN(4); /* ensure data is aligned so relocation can use 4-byte operations */ - _data = .; /* create a global symbol marking the start of the .data section */ - *(.data) /* all .data sections */ - *(.gnu.linkonce.d*) - } >ram /* put all the above into RAM (but load the LMA copy into FLASH) */ - . = ALIGN(4); /* ensure data is aligned so relocation can use 4-byte operations */ - _edata = .; /* define a global symbol marking the end of the .data section */ - _end = .; /* define a global symbol marking the end of application RAM */ - - __heap1_size = ORIGIN(ram) + LENGTH(ram) - . - __stack_size; - .heap1 (NOLOAD) : - { - PROVIDE(__heap1_start = .); - . = . + __heap1_size; - PROVIDE(__heap1_max = .); - } > ram - - /* - * Stacks - */ - .stack (NOLOAD) : - { - PROVIDE(__stack_start = .); - - . = . + __stack_usr_size; - __stack_usr_start = .; - . = . + __stack_und_size; - __stack_und_start = .; - . = . + __stack_fiq_size; - __stack_fiq_start = .; - . = . + __stack_irq_size; - __stack_irq_start = .; - . = . + __stack_abt_size; - __stack_abt_start = .; - . = . + __stack_svc_size; - __stack_svc_start = .; - - PROVIDE(__stack_end = .); - } > ram - - __heap2_size = LENGTH(ram_ethernet); - .heap2 (NOLOAD) : - { - PROVIDE(__heap2_start = . ); - . = . + __heap2_size; - PROVIDE(__heap2_max = .); /* _heap shall always be < _heap_max */ - } > ram_ethernet - - .usbdata (NOLOAD) : /* USB RAM section, may be used otherwise if USB is disabled */ - { - *(.usbdata) - } > ram_usb - - .batteryram (NOLOAD) : /* battery ram stay on during powerdown but needs to be handled specially */ - { - *(.batteryram) - } > ram_battery -} +/****************************************************************************** +Copyright 2008-2009, Freie Universitaet Berlin (FUB). All rights reserved. + +These sources were developed at the Freie Universitaet Berlin, Computer Systems +and Telematics group (http://cst.mi.fu-berlin.de). +------------------------------------------------------------------------------- +This file is part of FeuerWare. + +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +FeuerWare is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see http://www.gnu.org/licenses/ . +-------------------------------------------------------------------------------- +For further information and questions please use the web site + http://scatterweb.mi.fu-berlin.de +and the mailinglist (subscription via web site) + scatterweb@lists.spline.inf.fu-berlin.de +*******************************************************************************/ + +/* specify the LPC2387 memory areas (see LPC2387 datasheet page 15) */ +MEMORY +{ + flash : ORIGIN = 0, LENGTH = 512K /* FLASH ROM */ + infomem : ORIGIN = 0x0007D000, LENGTH = 4K /* Last sector in FLASH ROM for config data */ + ram_battery : ORIGIN = 0xE0084000, LENGTH = 2K /* Battery RAM */ + ram : ORIGIN = 0x40000000, LENGTH = 64K /* LOCAL ON-CHIP STATIC RAM */ + ram_usb : ORIGIN = 0x7FD00000, LENGTH = 16K /* USB RAM */ + ram_ethernet : ORIGIN = 0x7FE00000, LENGTH = 16K /* ethernet RAM */ +} + +__stack_und_size = 4; /* stack for "undefined instruction" interrupts */ +__stack_abt_size = 4; /* stack for "abort" interrupts */ +__stack_fiq_size = 64; /* stack for "FIQ" interrupts */ +__stack_irq_size = 400; /* stack for "IRQ" normal interrupts */ +__stack_svc_size = 400; /* stack for "SVC" supervisor mode */ +__stack_usr_size = 4096; /* stack for user operation (kernel init) */ +__stack_size = __stack_und_size + __stack_abt_size + __stack_fiq_size + __stack_irq_size + __stack_svc_size + __stack_usr_size; + +/* now define the output sections */ +SECTIONS +{ + .text : /* collect all sections that should go into FLASH after startup */ + { + *(.vectors) /* Exception Vectors and branch table >= 64 bytes */ + . = ALIGN(64); + *(.init) + *(.init0) /* Start here after reset. */ + *(.init1) + *(.init2) /* Copy data loop */ + *(.init3) + *(.init4) /* Clear bss */ + *(.init5) + *(.init6) /* C++ constructors. */ + *(.init7) + *(.init8) + *(.init9) /* Call main(). */ + + *(.text) /* all .text sections (code) */ + *(.text.*) + *(.gnu.linkonce.t.*) + + . = ALIGN(4); + __commands_start = .; + *(.commands) /* command table */ + __commands_end = .; + . = ALIGN(4); + __cfgspec_start = .; + *(.cfgspec) /* configuration spec table */ + __cfgspec_end = .; + . = ALIGN(4); + + __ctors_start = .; + PROVIDE (_os_ctor_start = .); + *(.ctors); + KEEP (*(.init_array)) + PROVIDE (_os_ctor_end = .); + __ctors_end = .; + *(.dtors); + LONG (0); + + + *(.rodata .rodata.*) /* all .rodata sections (constants, strings, etc.) */ + *(.gnu.linkonce.r.*) + *(.glue_7) /* all .glue_7 sections (no idea what these are) */ + *(.glue_7t) /* all .glue_7t sections (no idea what these are) */ + + *(.fini9) + *(.fini8) + *(.fini7) + *(.fini6) /* C++ destructors. */ + *(.fini5) + *(.fini4) + *(.fini3) + *(.fini2) + *(.fini1) + *(.fini0) /* Infinite loop after program termination. */ + *(.fini) + + *(.gcc_except_table) + + } >flash /* put all the above into FLASH */ + . = ALIGN(4); + _etext = . ; /* define a global symbol _etext just after the last code byte */ + + .config : + { + *(.configmem) + . = ALIGN(256); + } >infomem + . = ALIGN(4); + + /************************************************************************** + * RAM + **************************************************************************/ + + + .ctors (NOLOAD) : + { + . = ALIGN(4096); + start_ctors = .; + *(.init_array); + *(.ctors); + end_ctors = .; + } >ram + + .dtors (NOLOAD) : + { + . = ALIGN(4096); + start_dtors = .; + *(.fini_array); + *(.dtors); + end_dtors = .; + } >ram + + /* + * collect all uninitialized sections that go into RAM + */ + .noinit (NOLOAD) : + { + __noinit_start = .; + PROVIDE(__fiq_handler = .); + *(.fiq) + *(.noinit) + } > ram + . = ALIGN(4); + __noinit_end = .; + + /* + * collect all zero initialized sections that go into RAM + */ + .bss (NOLOAD) : + { + . = ALIGN(4); /* ensure data is aligned so relocation can use 4-byte operations */ + __bss_start = .; /* define a global symbol marking the start of the .bss section */ + *(.bss*) /* all .bss sections */ + *(COMMON) + } > ram /* put all the above in RAM (it will be cleared in the startup code */ + . = ALIGN(4); /* ensure data is aligned so relocation can use 4-byte operations */ + __bss_end = . ; /* define a global symbol marking the end of the .bss section */ + + /* + * collect all initialized .data sections that go into RAM + * initial values get placed at the end of .text in flash + */ + .data : AT (_etext) + { + . = ALIGN(4); /* ensure data is aligned so relocation can use 4-byte operations */ + _data = .; /* create a global symbol marking the start of the .data section */ + *(.data) /* all .data sections */ + *(.gnu.linkonce.d*) + } >ram /* put all the above into RAM (but load the LMA copy into FLASH) */ + . = ALIGN(4); /* ensure data is aligned so relocation can use 4-byte operations */ + _edata = .; /* define a global symbol marking the end of the .data section */ + _end = .; /* define a global symbol marking the end of application RAM */ + + __heap1_size = ORIGIN(ram) + LENGTH(ram) - . - __stack_size; + .heap1 (NOLOAD) : + { + PROVIDE(__heap1_start = .); + . = . + __heap1_size; + PROVIDE(__heap1_max = .); + } > ram + + /* + * Stacks + */ + .stack (NOLOAD) : + { + PROVIDE(__stack_start = .); + + . = . + __stack_usr_size; + __stack_usr_start = .; + . = . + __stack_und_size; + __stack_und_start = .; + . = . + __stack_fiq_size; + __stack_fiq_start = .; + . = . + __stack_irq_size; + __stack_irq_start = .; + . = . + __stack_abt_size; + __stack_abt_start = .; + . = . + __stack_svc_size; + __stack_svc_start = .; + + PROVIDE(__stack_end = .); + } > ram + + __heap2_size = LENGTH(ram_ethernet); + .heap2 (NOLOAD) : + { + PROVIDE(__heap2_start = . ); + . = . + __heap2_size; + PROVIDE(__heap2_max = .); /* _heap shall always be < _heap_max */ + } > ram_ethernet + + .usbdata (NOLOAD) : /* USB RAM section, may be used otherwise if USB is disabled */ + { + *(.usbdata) + } > ram_usb + + .batteryram (NOLOAD) : /* battery ram stay on during powerdown but needs to be handled specially */ + { + *(.batteryram) + } > ram_battery +} diff --git a/cpu/lpc2387/lpc2387-gpioint.c b/cpu/lpc2387/lpc2387-gpioint.c index e33fc854a..494172745 100644 --- a/cpu/lpc2387/lpc2387-gpioint.c +++ b/cpu/lpc2387/lpc2387-gpioint.c @@ -48,12 +48,12 @@ and the mailinglist (subscription via web site) #include "cpu.h" #include -struct irq_callback { +struct irq_callback_t { fp_irqcb callback; }; -static struct irq_callback gpioint0[32]; -static struct irq_callback gpioint2[32]; +static struct irq_callback_t gpioint0[32]; +static struct irq_callback_t gpioint2[32]; void gpioint_init(void) { @@ -68,7 +68,7 @@ void gpioint_init(void) { bool gpioint_set(int port, uint32_t bitmask, int flags, fp_irqcb callback) { - struct irq_callback* cbdata; + struct irq_callback_t* cbdata; unsigned long bit; volatile unsigned long* en_f; volatile unsigned long* en_r; @@ -123,7 +123,7 @@ gpioint_set(int port, uint32_t bitmask, int flags, fp_irqcb callback) return true; // success } /*---------------------------------------------------------------------------*/ -static void test_irq(int port, unsigned long f_mask, unsigned long r_mask, struct irq_callback* pcb) +static void __attribute__ ((__no_instrument_function__)) test_irq(int port, unsigned long f_mask, unsigned long r_mask, struct irq_callback_t* pcb) { /* Test each bit of rising and falling masks, if set trigger interrupt * on corresponding device */ @@ -148,7 +148,7 @@ void GPIO_IRQHandler(void) __attribute__((interrupt("IRQ"))); * Invoked whenever an activated gpio interrupt is triggered by a rising * or falling edge. */ -void GPIO_IRQHandler(void) { +void __attribute__ ((__no_instrument_function__)) GPIO_IRQHandler(void) { if( IO_INT_STAT & BIT0 ) { // interrupt(s) on PORT0 pending unsigned long int_stat_f = IO0_INT_STAT_F; // save content unsigned long int_stat_r = IO0_INT_STAT_R; // save content diff --git a/cpu/lpc2387/lpc2387-lpm.c b/cpu/lpc2387/lpc2387-lpm.c index d36829b1c..ff83433e3 100644 --- a/cpu/lpc2387/lpc2387-lpm.c +++ b/cpu/lpc2387/lpc2387-lpm.c @@ -55,22 +55,14 @@ static enum lpm_mode lpm; extern void init_clks1(void); extern void init_clks2(void); -#define DEBUG 0 -#if DEBUG -#include -#define PRINTF(...) printf(__VA_ARGS__) -#else -#define PRINTF(...) -#endif - +#define ENABLE_DEBUG 0 +#include -void -lpm_init(void) -{ +void lpm_init(void) { lpm = LPM_ON; } -#define LPM_DEBUG 0 +#define LPM_DEBUG 1 void lpm_begin_awake(void) { if (lpm >= LPM_SLEEP ) { // wake up from deep sleep @@ -96,7 +88,7 @@ void lpm_awake(void) { // Debug tests #if LPM_DEBUG usec = RTC_CTC-usec; - printf("Wakeup in %lu usecs\n",usec * 31); + DEBUG("Wakeup in %lu usecs\n",usec * 31); #endif } lpm = LPM_ON; @@ -118,8 +110,8 @@ enum lpm_mode lpm_set(enum lpm_mode target) { lpm = target; - #if DEBUG - PRINTF("# LPM power down %u -> %u", lpm, target); + #if iENABLE_DEBUG + DEBUG("# LPM power down %u -> %u", lpm, target); #endif PCON |= target_flags; // set target power mode diff --git a/cpu/lpc2387/lpc2387-mci.c b/cpu/lpc2387/lpc2387-mci.c new file mode 100644 index 000000000..f94174d13 --- /dev/null +++ b/cpu/lpc2387/lpc2387-mci.c @@ -0,0 +1,890 @@ +/*-----------------------------------------------------------------------*/ +/* MMCv3/SDv1/SDv2 (in native mode via MCI) control module (C)ChaN, 2010 */ +/*-----------------------------------------------------------------------*/ +/* This program is opened under license policy of following trems. +/ +/ Copyright (C) 2010, ChaN, all right reserved. +/ +/ * This program is a free software and there is NO WARRANTY. +/ * No restriction on use. You can use, modify and redistribute it for +/ personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY. +/ * Redistributions of source code must retain the above copyright notice. +/ +/---------------------------------------------------------------------------*/ + +#include +#include "lpc23xx.h" +#include "VIC.h" +#include "hwtimer.h" +#include "diskio.h" + +#define ENABLE_DEBUG +#include "debug.h" + +extern unsigned long hwtimer_now(void); + +/* --- MCI configurations --- */ +#define N_BUF 4 /* Block transfer FIFO depth (>= 2) */ +#define USE_4BIT 1 /* Use wide bus mode if SDC is detected */ +#define PCLK 36000000UL /* PCLK supplied to MCI module */ +#define MCLK_ID 400000UL /* MCICLK for ID state (100k-400k) */ +#define MCLK_RW 18000000UL /* MCICLK for data transfer (PCLK divided by even number) */ + +/* This MCI driver assumes that MCLK_RW is CCLK/4 or slower. If block buffer underrun/overrun +/ occured due to any interrupt by higher priority process or slow external memory, increasing +/ N_BUF or decreasing MCLK_RW will solve it. */ + + +/* ----- Port definitions ----- */ +#define SOCKINS !(FIO0PIN2 & 0x20) /* Card detect switch */ +#define SOCKWP (FIO0PIN2 & 0x04) /* Write protect switch */ + + +/* ----- MMC/SDC command ----- */ +#define CMD0 (0) /* GO_IDLE_STATE */ +#define CMD1 (1) /* SEND_OP_COND (MMC) */ +#define CMD2 (2) /* ALL_SEND_CID */ +#define CMD3 (3) /* SEND_RELATIVE_ADDR */ +#define ACMD6 (6|0x80) /* SET_BUS_WIDTH (SDC) */ +#define CMD7 (7) /* SELECT_CARD */ +#define CMD8 (8) /* SEND_IF_COND */ +#define CMD9 (9) /* SEND_CSD */ +#define CMD10 (10) /* SEND_CID */ +#define CMD12 (12) /* STOP_TRANSMISSION */ +#define CMD13 (13) /* SEND_STATUS */ +#define ACMD13 (13|0x80) /* SD_STATUS (SDC) */ +#define CMD16 (16) /* SET_BLOCKLEN */ +#define CMD17 (17) /* READ_SINGLE_BLOCK */ +#define CMD18 (18) /* READ_MULTIPLE_BLOCK */ +#define CMD23 (23) /* SET_BLK_COUNT (MMC) */ +#define ACMD23 (23|0x80) /* SET_WR_BLK_ERASE_COUNT (SDC) */ +#define CMD24 (24) /* WRITE_BLOCK */ +#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */ +#define CMD32 (32) /* ERASE_ER_BLK_START */ +#define CMD33 (33) /* ERASE_ER_BLK_END */ +#define CMD38 (38) /* ERASE */ +#define ACMD41 (41|0x80) /* SEND_OP_COND (SDC) */ +#define CMD55 (55) /* APP_CMD */ + +/* Card type flags (CardType) */ +#define CT_MMC 0x01 /* MMC ver 3 */ +#define CT_SD1 0x02 /* SD ver 1 */ +#define CT_SD2 0x04 /* SD ver 2 */ +#define CT_SDC (CT_SD1|CT_SD2) /* SD */ +#define CT_BLOCK 0x08 /* Block addressing */ + + +/*-------------------------------------------------------------------------- + + Module Private Functions + +---------------------------------------------------------------------------*/ + +static volatile DSTATUS Stat = STA_NOINIT; /* Disk status */ + +static unsigned short CardRCA; /* Assigned RCA */ +static unsigned char CardType, /* Card type flag */ + CardInfo[16+16+4]; /* CSD(16), CID(16), OCR(4) */ + +static volatile unsigned char XferStat, /* b3:MCI error, b2:Overrun, b1:Write, b0:Read */ + XferWc, /* Write block counter */ + XferWp, XferRp; /* R/W index of block FIFO */ + +static unsigned long DmaBuff[N_BUF][128] __attribute__ ((section(".usbdata"))); /* Block transfer FIFO */ +static unsigned long LinkList [N_BUF][4] __attribute__ ((section(".usbdata"))); /* DMA link list */ + +void Isr_MCI (void) __attribute__ ((interrupt("IRQ"))); +void Isr_GPDMA (void) __attribute__ ((interrupt("IRQ"))); + +/*-----------------------------------------------------------------------*/ +/* Interrupt service routine for data transfer */ +/*-----------------------------------------------------------------------*/ + +void Isr_MCI (void) { + unsigned long ms; + unsigned char n, xs; + + ms = MCI_STATUS & 0x073A; /* Clear MCI interrupt status */ + MCI_CLEAR = ms; + + xs = XferStat; + if (ms & 0x400) { /* A block transfer completed (DataBlockEnd) */ + if (xs & 1) { /* In card read operation */ + if (ms & 0x100) /* When last block is received (DataEnd), */ + GPDMA_SOFT_BREQ = 0x10; /* Pop off remaining data in the MCIFIFO */ + n = (XferWp + 1) % N_BUF; /* Next write buffer */ + XferWp = n; + if (n == XferRp) xs |= 4; /* Check block overrun */ + } + else { /* In card write operation */ + n = (XferRp + 1) % N_BUF; /* Next read buffer */ + XferRp = n; + if (n == XferWp) xs |= 4; /* Check block underrun */ + } + } + else { /* An MCI error occured (not DataBlockEnd) */ + xs |= 8; + } + + XferStat = xs; + + VICVectAddr = 0; +} + +void Isr_GPDMA (void) { + if(GPDMA_INT_TCSTAT & BIT0) + { + GPDMA_INT_TCCLR = 0x01; /* Clear GPDMA interrupt flag */ + if (XferStat & 2) + { + /* In write operation */ + if (--XferWc == N_BUF) /* Terminate LLI */ + { + LinkList[XferRp % N_BUF][2] = 0; + } + } + } + else + { + GPDMA_INT_TCCLR = 0x3; + } + + VICVectAddr = 0; +} + + +/*-----------------------------------------------------------------------*/ +/* Ready for data reception */ +/*-----------------------------------------------------------------------*/ + +/** + * @param blks Number of blocks to receive (1..127) + * @param bs Block size (64 or 512) + * */ +static void ready_reception (unsigned int blks, unsigned int bs) { + unsigned int n; + unsigned long dma_ctrl; + + /* ------ Setting up GPDMA Ch-0 ------ */ + GPDMA_CH0_CFG &= 0xFFF80420; /* Disable ch-0 */ + GPDMA_INT_TCCLR = 0x01; /* Clear interrupt flag */ + dma_ctrl = 0x88492000 | (bs / 4); /* 1_000_1_0_00_010_010_010_010_************ */ + + /* Create link list */ + for (n = 0; n < N_BUF; n++) { + LinkList[n][0] = (unsigned long)&MCI_FIFO; + LinkList[n][1] = (unsigned long)DmaBuff[n]; + LinkList[n][2] = (unsigned long)LinkList[(n + 1) % N_BUF]; + LinkList[n][3] = dma_ctrl; + } + + /* Load first LLI */ + GPDMA_CH0_SRC = LinkList[0][0]; + GPDMA_CH0_DEST = LinkList[0][1]; + GPDMA_CH0_LLI = LinkList[0][2]; + GPDMA_CH0_CTRL = LinkList[0][3]; + + /* Enable ch-0 */ + GPDMA_CH0_CFG |= 0x19009; /* *************_0_0_1_1_0_010_*_0000_*_0100_1 */ + + /* --------- Setting up MCI ---------- */ + + XferRp = 0; XferWp = 0; /* Block FIFO R/W index */ + XferStat = 1; /* Transfer status: MCI --> Memory */ + + MCI_DATA_LEN = bs * blks; /* Set total data length */ + MCI_DATA_TMR = (unsigned long)(MCLK_RW * 0.2); /* Data timer: 0.2sec */ + MCI_CLEAR = 0x72A; /* Clear status flags */ + MCI_MASK0 = 0x72A; /* DataBlockEnd StartBitErr DataEnd RxOverrun DataTimeOut DataCrcFail */ + for (n = 0; bs > 1; bs >>= 1, n += 0x10); + MCI_DATA_CTRL = n | 0xB; /* Start to receive data blocks */ +} + + +/*-----------------------------------------------------------------------*/ +/* Start to transmit a data block */ +/*-----------------------------------------------------------------------*/ + +#if _READONLY == 0 +/* + * @param blks Number of blocks to be transmitted (1..127) + * */ +static void start_transmission ( unsigned char blks) { + unsigned int n; + unsigned long dma_ctrl; + + + /* ------ Setting up GPDMA Ch-0 ------ */ + + GPDMA_CH0_CFG &= 0xFFF80420; /* Disable ch-0 */ + GPDMA_INT_TCCLR = 0x01; /* Clear interrupt flag */ + dma_ctrl = 0x84492080; /* 1_000_0_1_00_010_010_010_010_000010000000 */ + + /* Create link list */ + for (n = 0; n < N_BUF; n++) { + LinkList[n][0] = (unsigned long)DmaBuff[n]; + LinkList[n][1] = (unsigned long)&MCI_FIFO; + LinkList[n][2] = (n == blks - 1) ? 0 : (unsigned long)LinkList[(n + 1) % N_BUF]; + LinkList[n][3] = dma_ctrl; + } + + /* Load first LLI */ + GPDMA_CH0_SRC = LinkList[0][0]; + GPDMA_CH0_DEST = LinkList[0][1]; + GPDMA_CH0_LLI = LinkList[0][2]; + GPDMA_CH0_CTRL = LinkList[0][3]; + + /* Enable ch-0 */ + GPDMA_CH0_CFG |= 0x18901; /* *************_0_0_1_1_0_001_*_0100_*_0000_1 */ + + /* --------- Setting up MCI ---------- */ + + XferRp = 0; /* Block FIFO read index */ + XferWc = blks; + XferStat = 2; /* Transfer status: Memroy --> MCI */ + + MCI_DATA_LEN = 512 * (blks + 1); /* Set total data length */ + MCI_DATA_TMR = (unsigned long)(MCLK_RW * 0.5); /* Data timer: 0.5sec */ + MCI_CLEAR = 0x51A; /* Clear status flags */ + MCI_MASK0 = 0x51A; /* DataBlockEnd DataEnd TxUnderrun DataTimeOut DataCrcFail */ + MCI_DATA_CTRL = (9 << 4) | 0x9; /* Start to transmit data blocks */ +} +#endif /* _READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Stop data transfer */ +/*-----------------------------------------------------------------------*/ + +static void stop_transfer (void) { + MCI_MASK0 = 0; /* Disable MCI interrupt */ + MCI_DATA_CTRL = 0; /* Stop MCI data transfer */ + + GPDMA_CH0_CFG &= 0xFFF80420; /* Disable DMA ch-0 */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Power Control (Device dependent) */ +/*-----------------------------------------------------------------------*/ + +static int power_status (void) { + return (MCI_POWER & 3) ? 1 : 0; +} + + +static void power_on (void) { + /* Enable MCI and GPDMA clock */ + PCONP |= (3 << 28); + + /* Enable GPDMA controller with little-endian */ + GPDMA_CH0_CFG &= 0xFFF80000; /* Disable DMA ch-0 */ + GPDMA_CONFIG = 0x01; + + /* Select PCLK for MCI, CCLK/2 = 36MHz */ + PCLKSEL1 = (PCLKSEL1 & 0xFCFFFFFF) | 0x02000000; + + //0.19 0.20 0.21 0.22 + PINMODE1 &= ~( (BIT6 | BIT7) | (BIT8 | BIT9) | (BIT10 | BIT11) | (BIT12 | BIT13) ); + PINMODE1 |= (BIT7) | (BIT9) | (BIT11) | (BIT13); // no resistors + //2.11 2.12 2.13 + PINMODE4 &= ~( (BIT22 | BIT23) | (BIT24 | BIT25) | (BIT26 | BIT27) ); + PINMODE4 |= (BIT23) | (BIT25) | (BIT27); // no resistors + /* Attach MCI unit to I/O pad */ + PINSEL1 = (PINSEL1 & 0xFFFFC03F) | 0x00002A80; /* MCICLK, MCICMD, MCIDATA0, MCIPWR */ +#if USE_4BIT + PINSEL4 = (PINSEL4 & 0xF03FFFFF) | 0x0A800000; /* MCIDATA1-3 */ +#endif + MCI_MASK0 = 0; + MCI_COMMAND = 0; + MCI_DATA_CTRL = 0; + + // pin 0.21 high active + SCS |= 0x08; + + /* Register interrupt handlers for MCI,DMA event */ + //RegisterIrq(MCI_INT, Isr_MCI, PRI_LOWEST-1); + install_irq( MCI_INT, (void *)Isr_MCI, 5 ); + + //RegisterIrq(GPDMA_INT, Isr_GPDMA, PRI_LOWEST-1); + install_irq( GPDMA_INT, (void *)Isr_GPDMA, 5 ); + + + /* Power-on (VCC is always tied to the socket on this board) */ + MCI_POWER = 0x01; /* Power on */ + + //for (Timer[0] = 10; Timer[0]; ) ; /* 10ms */ + hwtimer_wait(1000); + + MCI_POWER = 0x03; /* Enable signals */ +} + + +static void power_off (void) { + MCI_MASK0 = 0; + MCI_COMMAND = 0; + MCI_DATA_CTRL = 0; + + MCI_POWER = 0; /* Power-off */ + MCI_CLOCK = 0; + + // pin 0.21 low inactive + SCS &= ~0x08; + + //0.21 MCI led Pin (turns sd card off, too) + //0.19 0.20 0.21 0.22 with pull-down + PINMODE1 |= (BIT6 | BIT7) | (BIT8 | BIT9) | (BIT10 | BIT11) | (BIT12 | BIT13); + PINSEL1 &= ~( (BIT6 | BIT7) | (BIT8 | BIT9) | (BIT10 | BIT11) | (BIT12 | BIT13) ); +// Pins should be now configured as standard input (see board_init.c if you accidentally reconfigured them) + + //2.11 2.12 2.13 with pull-down + PINMODE4 |= (BIT22 | BIT23) | (BIT24 | BIT25) | (BIT26 | BIT27); + PINSEL4 &= ~( (BIT22 | BIT23) | (BIT24 | BIT25) | (BIT26 | BIT27) ); +// Pins should be now configured as standard input (see board_init.c if you accidentally reconfigured them) + + Stat |= STA_NOINIT; +} + + +/*-----------------------------------------------------------------------*/ +/* Send a command packet to the card and receive a response */ +/*-----------------------------------------------------------------------*/ + +/* + * @param idx Command index (bit[5..0]), ACMD flag (bit7) + * @param arg Command argument + * @param rt Expected response type. None(0), Short(1) or Long(2) + * @param *buff Response return buffer + * @return 1 when function succeeded otherwise returns 0 + * */ +static int send_cmd (unsigned int idx, unsigned long arg, unsigned int rt, unsigned long *buff) { + unsigned int s, mc; + + if (idx & 0x80) { /* Send a CMD55 prior to the specified command if it is ACMD class */ + if (!send_cmd(CMD55, (unsigned long)CardRCA << 16, 1, buff) /* When CMD55 is faild, */ + || !(buff[0] & 0x00000020)) return 0; /* exit with error */ + } + idx &= 0x3F; /* Mask out ACMD flag */ + + do { /* Wait while CmdActive bit is set */ + MCI_COMMAND = 0; /* Cancel to transmit command */ + MCI_CLEAR = 0x0C5; /* Clear status flags */ + for (s = 0; s < 10; s++) MCI_STATUS; /* Skip lock out time of command reg. */ + } while (MCI_STATUS & 0x00800); + + MCI_ARGUMENT = arg; /* Set the argument into argument register */ + mc = 0x400 | idx; /* Enable bit + index */ + if (rt == 1) mc |= 0x040; /* Set Response bit to reveice short resp */ + if (rt > 1) mc |= 0x0C0; /* Set Response and LongResp bit to receive long resp */ + MCI_COMMAND = mc; /* Initiate command transaction */ + + //Timer[1] = 100; + uint32_t timerstart = hwtimer_now(); + + for (;;) { /* Wait for end of the cmd/resp transaction */ + + //if (!Timer[1]) return 0; + if(hwtimer_now() - timerstart > 10000) + { + return 0; + } + + s = MCI_STATUS; /* Get the transaction status */ + + if (rt == 0) + { + if (s & 0x080) + return 1; /* CmdSent */ + } + else + { + if (s & 0x040) + break; /* CmdRespEnd */ + if (s & 0x001) + { /* CmdCrcFail */ + if (idx == 1 || idx == 12 || idx == 41) /* Ignore CRC error on CMD1/12/41 */ + break; + return 0; + } + if (s & 0x004) + return 0; /* CmdTimeOut */ + } + } + + buff[0] = MCI_RESP0; /* Read the response words */ + if (rt == 2) { + buff[1] = MCI_RESP1; + buff[2] = MCI_RESP2; + buff[3] = MCI_RESP3; + } + + return 1; /* Return with success */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Wait card ready */ +/*-----------------------------------------------------------------------*/ + +/** + * @param tmr Timeout in unit of 1ms + * @returns 1 when card is tran state, otherwise returns 0 + */ +static int wait_ready (unsigned short tmr) { + unsigned long rc; + + uint32_t stoppoll = hwtimer_now() + tmr * 100; + bool bBreak = false; + while (hwtimer_now() < stoppoll/*Timer[0]*/) + { + if (send_cmd(CMD13, (unsigned long) CardRCA << 16, 1, &rc) && ((rc & 0x01E00) == 0x00800)) + { + bBreak = true; + break; + } + /* This loop will take a time. Insert rot_rdq() here for multitask envilonment. */ + } + return bBreak;//Timer[0] ? 1 : 0; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Swap byte order */ +/*-----------------------------------------------------------------------*/ +static void bswap_cp (unsigned char *dst, const unsigned long *src) { + unsigned long d; + + + d = *src; + *dst++ = (unsigned char)(d >> 24); + *dst++ = (unsigned char)(d >> 16); + *dst++ = (unsigned char)(d >> 8); + *dst++ = (unsigned char)(d >> 0); +} + + + + +/*-------------------------------------------------------------------------- + + Public Functions + +---------------------------------------------------------------------------*/ + + +/*-----------------------------------------------------------------------*/ +/* Initialize Disk Drive */ +/*-----------------------------------------------------------------------*/ +DSTATUS MCI_initialize (void) { + unsigned int cmd, n; + unsigned long resp[4]; + unsigned char ty; + + if (Stat & STA_NODISK) return Stat; /* No card in the socket */ + + power_off(); + + hwtimer_wait(HWTIMER_TICKS(1000)); + + power_on(); /* Force socket power on */ + MCI_CLOCK = 0x100 | (PCLK/MCLK_ID/2-1); /* Set MCICLK = MCLK_ID */ + //for (Timer[0] = 2; Timer[0]; ); + hwtimer_wait(250); + + send_cmd(CMD0, 0, 0, NULL); /* Enter idle state */ + CardRCA = 0; + + /*---- Card is 'idle' state ----*/ + + /* Initialization timeout of 1000 msec */ + uint32_t start = hwtimer_now(); + + /* SDC Ver2 */ + if (send_cmd(CMD8, 0x1AA, 1, resp) && (resp[0] & 0xFFF) == 0x1AA) { + /* The card can work at vdd range of 2.7-3.6V */ + DEBUG("SDC Ver. 2\n"); + + do { /* Wait while card is busy state (use ACMD41 with HCS bit) */ + /* This loop will take a time. Insert wai_tsk(1) here for multitask envilonment. */ + if (hwtimer_now() > start + 1000000/*!Timer[0]*/) { + DEBUG("%s, %d: Timeout #1\n", __FILE__, __LINE__); + goto di_fail; + } + } while (!send_cmd(ACMD41, 0x40FF8000, 1, resp) || !(resp[0] & 0x80000000)); + + ty = (resp[0] & 0x40000000) ? CT_SD2|CT_BLOCK : CT_SD2; /* Check CCS bit in the OCR */ + } + else { /* SDC Ver1 or MMC */ + if (send_cmd(ACMD41, 0x00FF8000, 1, resp)) { + DEBUG("SDC Ver. 1\n"); + ty = CT_SD1; + cmd = ACMD41; /* ACMD41 is accepted -> SDC Ver1 */ + } + else { + DEBUG("MMC\n"); + ty = CT_MMC; + cmd = CMD1; /* ACMD41 is rejected -> MMC */ + } + do { /* Wait while card is busy state (use ACMD41 or CMD1) */ + DEBUG("%s, %d: %lX\n", __FILE__, __LINE__, resp[0]); + /* This loop will take a time. Insert wai_tsk(1) here for multitask envilonment. */ + if (hwtimer_now() > start + 1000000/*!Timer[0]*/) { + DEBUG("now: %lu, started at: %lu\n", hwtimer_now(), start); + DEBUG("%s, %d: Timeout #2\n", __FILE__, __LINE__); + goto di_fail; + } + } while (!send_cmd(cmd, 0x00FF8000, 1, resp) || !(resp[0] & 0x80000000)); + } + + CardType = ty; /* Save card type */ + bswap_cp(&CardInfo[32], resp); /* Save OCR */ + + /*---- Card is 'ready' state ----*/ + + if (!send_cmd(CMD2, 0, 2, resp)) { + DEBUG("%s, %d: Failed entering ident state", __FILE__, __LINE__); + goto di_fail; /* Enter ident state */ + } + for (n = 0; n < 4; n++) bswap_cp(&CardInfo[n * 4 + 16], &resp[n]); /* Save CID */ + + /*---- Card is 'ident' state ----*/ + + if (ty & CT_SDC) { /* SDC: Get generated RCA and save it */ + if (!send_cmd(CMD3, 0, 1, resp)) { + DEBUG("%s, %d: Failed generating RCA\n", __FILE__, __LINE__); + goto di_fail; + } + CardRCA = (unsigned short)(resp[0] >> 16); + } else { /* MMC: Assign RCA to the card */ + if (!send_cmd(CMD3, 1 << 16, 1, resp)) goto di_fail; + CardRCA = 1; + } + + /*---- Card is 'stby' state ----*/ + + if (!send_cmd(CMD9, (unsigned long)CardRCA << 16, 2, resp)) /* Get CSD and save it */ + { + //printf("MCI CMD9 fail\n"); + goto di_fail; + } + for (n = 0; n < 4; n++) bswap_cp(&CardInfo[n * 4], &resp[n]); + + if (!send_cmd(CMD7, (unsigned long)CardRCA << 16, 1, resp)) /* Select card */ + { + //printf("MCI CMD7 fail\n"); + goto di_fail; + } + + /*---- Card is 'tran' state ----*/ + + if (!(ty & CT_BLOCK)) { /* Set data block length to 512 (for byte addressing cards) */ + if (!send_cmd(CMD16, 512, 1, resp) || (resp[0] & 0xFDF90000)) + { + //printf("MCI CMD16 fail\n"); + goto di_fail; + } + } + +#if USE_4BIT + if (ty & CT_SDC) { /* Set wide bus mode (for SDCs) */ + if (!send_cmd(ACMD6, 2, 1, resp) /* Set bus mode of SDC */ + || (resp[0] & 0xFDF90000)) + { + //printf("MCI ACMD6 fail\n"); + goto di_fail; + } + MCI_CLOCK |= 0x800; /* Set bus mode of MCI */ + } +#endif + + MCI_CLOCK = (MCI_CLOCK & 0xF00) | 0x200 | (PCLK/MCLK_RW/2-1); /* Set MCICLK = MCLK_RW, power-save mode */ + + Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */ + return Stat; + +di_fail: + power_off(); + Stat |= STA_NOINIT; /* Set STA_NOINIT */ + return Stat; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Get Disk Status */ +/*-----------------------------------------------------------------------*/ + +DSTATUS MCI_status (void) { + return Stat; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Read Sector(s) */ +/*-----------------------------------------------------------------------*/ + +/** + * @param buff Pointer to the data buffer to store read data + * @param sector Start sector number (LBA) + * @param count Sector count (1..127) + */ +DRESULT MCI_read (unsigned char *buff, unsigned long sector, unsigned char count) { + unsigned long resp; + unsigned int cmd; + unsigned char rp; + + + if (count < 1 || count > 127) return RES_PARERR; /* Check parameter */ + if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check drive status */ + + if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert LBA to byte address if needed */ + if (!wait_ready(500)) return RES_ERROR; /* Make sure that card is tran state */ + + ready_reception(count, 512); /* Ready to receive data blocks */ + + cmd = (count > 1) ? CMD18 : CMD17; /* Transfer type: Single block or Multiple block */ + + if (send_cmd(cmd, sector, 1, &resp) /* Start to read */ + && !(resp & 0xC0580000)) + { + rp = 0; + do + { + while ((rp == XferWp) && !(XferStat & 0xC)) + { /* Wait for block arrival */ + /* This loop will take a time. Replace it with sync process for multitask envilonment. */ + } + if (XferStat & 0xC) + { + break; /* Abort if any error has occured */ + } + + Copy_al2un(buff, DmaBuff[rp], 512); /* Pop an block */ + + XferRp = rp = (rp + 1) % N_BUF; /* Next DMA buffer */ + if (XferStat & 0xC) + { + break; /* Abort if overrun has occured */ + } + buff += 512; /* Next user buffer address */ + } + while (--count); + if (cmd == CMD18) /* Terminate to read (MB) */ + send_cmd(CMD12, 0, 1, &resp); + } + + stop_transfer(); /* Close data path */ + + return count ? RES_ERROR : RES_OK; +} + + +/*-----------------------------------------------------------------------*/ +/* Write Sector(s) */ +/*-----------------------------------------------------------------------*/ + +#if _READONLY == 0 + +/** + * @param buff Pointer to the data to be written + * @param sector Start sector number (LBA) + * @param count Sector count (1..127) + * */ +DRESULT MCI_write (const unsigned char *buff, unsigned long sector, unsigned char count) { + unsigned long rc; + unsigned int cmd; + unsigned char wp, xc; + + if (count < 1 || count > 127) return RES_PARERR; /* Check parameter */ + if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check drive status */ + if (Stat & STA_PROTECT) return RES_WRPRT; /* Check write protection */ + + if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert LBA to byte address if needed */ + if (!wait_ready(500)) return RES_ERROR; /* Make sure that card is tran state */ + + if (count == 1) { /* Single block write */ + cmd = CMD24; + } + else { /* Multiple block write */ + cmd = (CardType & CT_SDC) ? ACMD23 : CMD23; + if (!send_cmd(cmd, count, 1, &rc) /* Preset number of blocks to write */ + || (rc & 0xC0580000)) { + return RES_ERROR; + } + cmd = CMD25; + } + + if (!send_cmd(cmd, sector, 1, &rc) /* Send a write command */ + || (rc & 0xC0580000)) { + return RES_ERROR; + } + + wp = 0; + xc = count; + do { /* Fill block FIFO */ + Copy_un2al(DmaBuff[wp], (unsigned char*)(unsigned int)buff, 512); /* Push a block */ + wp++; /* Next DMA buffer */ + count--; + buff += 512; /* Next user buffer address */ + } while (count && wp < N_BUF); + XferWp = wp = wp % N_BUF; + start_transmission(xc); /* Start transmission */ + + while (count) { + while((wp == XferRp) && !(XferStat & 0xC)) { /* Wait for block FIFO not full */ + /* This loop will take a time. Replace it with sync process for multitask envilonment. */ + } + if (XferStat & 0xC) break; /* Abort if block underrun or any MCI error has occured */ + Copy_un2al(DmaBuff[wp], (unsigned char*)(unsigned int)buff, 512); /* Push a block */ + XferWp = wp = (wp + 1) % N_BUF; /* Next DMA buffer */ + if (XferStat & 0xC) break; /* Abort if block underrun has occured */ + count--; + buff += 512; /* Next user buffer address */ + } + + while (!(XferStat & 0xC)); /* Wait for all blocks sent (block underrun) */ + if (XferStat & 0x8) count = 1; /* Abort if any MCI error has occured */ + + stop_transfer(); /* Close data path */ + if (cmd == CMD25 && (CardType & CT_SDC)) /* Terminate to write (SDC w/MB) */ + send_cmd(CMD12, 0, 1, &rc); + + return count ? RES_ERROR : RES_OK; +} +#endif /* _READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Miscellaneous Functions */ +/*-----------------------------------------------------------------------*/ + +DRESULT MCI_ioctl ( + unsigned char ctrl, /* Control code */ + void *buff /* Buffer to send/receive data block */ +) +{ + DRESULT res; + unsigned char b, *ptr = buff; + unsigned long resp[4], d, *dp, st, ed; + + + if (Stat & STA_NOINIT) return RES_NOTRDY; + + res = RES_ERROR; + + switch (ctrl) { + case CTRL_SYNC : /* Make sure that all data has been written on the media */ + if (wait_ready(500)) /* Wait for card enters tarn state */ + res = RES_OK; + break; + + case GET_SECTOR_COUNT : /* Get number of sectors on the disk (unsigned long) */ + if ((CardInfo[0] >> 6) == 1) { /* SDC CSD v2.0 */ + d = ((unsigned short)CardInfo[8] << 8) + CardInfo[9] + 1; + *(unsigned long*)buff = d << 10; + } else { /* MMC or SDC CSD v1.0 */ + b = (CardInfo[5] & 15) + ((CardInfo[10] & 128) >> 7) + ((CardInfo[9] & 3) << 1) + 2; + d = (CardInfo[8] >> 6) + ((unsigned short)CardInfo[7] << 2) + ((unsigned short)(CardInfo[6] & 3) << 10) + 1; + *(unsigned long*)buff = d << (b - 9); + } + res = RES_OK; + break; + + case GET_SECTOR_SIZE : /* Get sectors on the disk (unsigned short) */ + *(unsigned short*)buff = 512; + res = RES_OK; + break; + + case GET_BLOCK_SIZE : /* Get erase block size in unit of sectors (unsigned long) */ + if (CardType & CT_SD2) { /* SDC ver 2.00 */ + *(unsigned long*)buff = 16UL << (CardInfo[10] >> 4); + } else { /* SDC ver 1.XX or MMC */ + if (CardType & CT_SD1) /* SDC v1 */ + *(unsigned long*)buff = (((CardInfo[10] & 63) << 1) + ((unsigned short)(CardInfo[11] & 128) >> 7) + 1) << ((CardInfo[13] >> 6) - 1); + else /* MMC */ + *(unsigned long*)buff = ((unsigned short)((CardInfo[10] & 124) >> 2) + 1) * (((CardInfo[11] & 3) << 3) + ((CardInfo[11] & 224) >> 5) + 1); + } + res = RES_OK; + break; + + case CTRL_ERASE_SECTOR : /* Erase a block of sectors */ + if (!(CardType & CT_SDC) || (!(CardInfo[0] >> 6) && !(CardInfo[10] & 0x40))) break; /* Check if sector erase can be applied to the card */ + dp = buff; st = dp[0]; ed = dp[1]; + if (!(CardType & CT_BLOCK)) { + st *= 512; ed *= 512; + } + if (send_cmd(CMD32, st, 1, resp) && send_cmd(CMD33, ed, 1, resp) && send_cmd(CMD38, 0, 1, resp) && wait_ready(30000)) + res = RES_OK; + break; + + case CTRL_POWER : + switch (ptr[0]) { + case 0: /* Sub control code == 0 (POWER_OFF) */ + power_off(); /* Power off */ + res = RES_OK; + break; + case 1: /* Sub control code == 1 (POWER_GET) */ + ptr[1] = (unsigned char)power_status(); + res = RES_OK; + break; + default : + res = RES_PARERR; + } + break; + + case MMC_GET_TYPE : /* Get card type flags (1 byte) */ + *ptr = CardType; + res = RES_OK; + break; + + case MMC_GET_CSD : /* Get CSD (16 bytes) */ + memcpy(buff, &CardInfo[0], 16); + res = RES_OK; + break; + + case MMC_GET_CID : /* Get CID (16 bytes) */ + memcpy(buff, &CardInfo[16], 16); + res = RES_OK; + break; + + case MMC_GET_OCR : /* Get OCR (4 bytes) */ + memcpy(buff, &CardInfo[32], 4); + res = RES_OK; + break; + + case MMC_GET_SDSTAT : /* Receive SD status as a data block (64 bytes) */ + if (CardType & CT_SDC) { /* SDC */ + if (wait_ready(500)) { + ready_reception(1, 64); /* Ready to receive data blocks */ + if (send_cmd(ACMD13, 0, 1, resp) /* Start to read */ + && !(resp[0] & 0xC0580000)) { + while ((XferWp == 0) && !(XferStat & 0xC)); + if (!(XferStat & 0xC)) { + Copy_al2un(buff, DmaBuff[0], 64); + res = RES_OK; + } + } + } + stop_transfer(); /* Close data path */ + } + break; + + default: + res = RES_PARERR; + } + + return res; +} diff --git a/cpu/lpc2387/lpc2387-rtc.c b/cpu/lpc2387/lpc2387-rtc.c index 03028343b..4642042a6 100644 --- a/cpu/lpc2387/lpc2387-rtc.c +++ b/cpu/lpc2387/lpc2387-rtc.c @@ -49,14 +49,8 @@ and the mailinglist (subscription via web site) #define PREINT_RTC 0x000001C8 /* Prescaler value, integer portion, PCLK = 15Mhz */ #define PREFRAC_RTC 0x000061C0 /* Prescaler value, fraction portion, PCLK = 15Mhz */ -#define DEBUG 0 -#if DEBUG -#include -#define PRINTF(fmt, args...) printf("rtc: " fmt "\n", ##args) -#else -#define PRINTF(fmt, args...) -#endif - +#define ENABLE_DEBUG 0 +#include /** * @brief epoch time in hour granularity @@ -68,7 +62,7 @@ static volatile time_t epoch; * @brief Sets the current time in broken down format directly from to RTC * @param[in] localt Pointer to structure with time to set */ -static void +void rtc_set_localtime(struct tm* localt) { if( localt == NULL ) @@ -93,14 +87,14 @@ void rtc_set(time_t time) { } /*---------------------------------------------------------------------------*/ /// set clock to start of unix epoch -void _rtc_reset(void) +void rtc_reset(void) { rtc_set(0); epoch = 0; } /*---------------------------------------------------------------------------*/ void -_rtc_set_alarm(struct tm* localt, enum rtc_alarm_mask mask) +rtc_set_alarm(struct tm* localt, enum rtc_alarm_mask mask) { if( localt != NULL ) { RTC_ALSEC = localt->tm_sec; @@ -112,7 +106,7 @@ _rtc_set_alarm(struct tm* localt, enum rtc_alarm_mask mask) RTC_ALMON = localt->tm_mon + 1; RTC_ALYEAR = localt->tm_year; RTC_AMR = ~mask; // set wich alarm fields to check - PRINTF("alarm set %2lu.%2lu.%4lu %2lu:%2lu:%2lu", + DEBUG("alarm set %2lu.%2lu.%4lu %2lu:%2lu:%2lu\n", RTC_ALDOM, RTC_ALMON, RTC_ALYEAR, RTC_ALHOUR, RTC_ALMIN, RTC_ALSEC); } else { RTC_AMR = 0xff; @@ -120,7 +114,7 @@ _rtc_set_alarm(struct tm* localt, enum rtc_alarm_mask mask) } /*---------------------------------------------------------------------------*/ enum rtc_alarm_mask -_rtc_get_alarm(struct tm* localt) +rtc_get_alarm(struct tm* localt) { if( localt != NULL ) { localt->tm_sec = RTC_ALSEC; @@ -151,7 +145,7 @@ void RTC_IRQHandler (void) } else if( RTC_ILR & ILR_RTCALF ) { RTC_ILR |= ILR_RTCALF; RTC_AMR = 0xff; // disable alarm irq - PRINTF("alarm"); + DEBUG("Ring\n"); lpm_end_awake(); } @@ -183,10 +177,10 @@ void rtc_init(void) /* initialize clock with valid unix compatible values * If RTC_YEAR contains an value larger unix time_t we must reset. */ if( RTC_YEAR > 2037 ) { - _rtc_reset(); + rtc_reset(); } - PRINTF("%2lu.%2lu.%4lu %2lu:%2lu:%2lu epoch %lu", + DEBUG("%2lu.%2lu.%4lu %2lu:%2lu:%2lu epoch %lu\n", RTC_DOM, RTC_MONTH, RTC_YEAR, RTC_HOUR, RTC_MIN, RTC_SEC, epoch); } @@ -242,7 +236,7 @@ rtc_get_localtime(struct tm* localt) } } /*---------------------------------------------------------------------------*/ -void _gettimeofday_r(struct _reent *r, struct timeval *ptimeval, struct timezone *ptimezone) +void gettimeofday_r(struct _reent *r, struct timeval *ptimeval, struct timezone *ptimezone) { r->_errno = 0; if( ptimeval != NULL ) { diff --git a/cpu/lpc2387/lpc23xx-iap.c b/cpu/lpc2387/lpc23xx-iap.c new file mode 100644 index 000000000..7b49fe74e --- /dev/null +++ b/cpu/lpc2387/lpc23xx-iap.c @@ -0,0 +1,94 @@ +#include +#include +#include + +uint8_t iap_get_sector(uint32_t addr) { + if ((addr >=0x00000000) && (addr <= 0x00000FFF)) { + return 0; + } + if ((addr >=0x00001000) && (addr <= 0x00001FFF)) { + return 1; + } + if ((addr >=0x00002000) && (addr <= 0x00002FFF)) { + return 2; + } + if ((addr >=0x00003000) && (addr <= 0x00003FFF)) { + return 3; + } + if ((addr >=0x00004000) && (addr <= 0x00004FFF)) { + return 4; + } + if ((addr >=0x00005000) && (addr <= 0x00005FFF)) { + return 5; + } + if ((addr >=0x00006000) && (addr <= 0x00006FFF)) { + return 6; + } + if ((addr >=0x00007000) && (addr <= 0x00007FFF)) { + return 7; + } + + if ((addr >=0x00008000) && (addr <= 0x0000FFFF)) { + return 8; + } + if ((addr >=0x00010000) && (addr <= 0x00017FFF)) { + return 9; + } + if ((addr >=0x00018000) && (addr <= 0x0001FFFF)) { + return 10; + } + if ((addr >=0x00020000) && (addr <= 0x00027FFF)) { + return 11; + } + if ((addr >=0x00028000) && (addr <= 0x0002FFFF)) { + return 12; + } + if ((addr >=0x00030000) && (addr <= 0x00037FFF)) { + return 13; + } + if ((addr >=0x00038000) && (addr <= 0x0003FFFF)) { + return 14; + } + if ((addr >=0x00040000) && (addr <= 0x00047FFF)) { + return 15; + } + if ((addr >=0x00048000) && (addr <= 0x0004FFFF)) { + return 16; + } + if ((addr >=0x00050000) && (addr <= 0x00057FFF)) { + return 17; + } + if ((addr >=0x00058000) && (addr <= 0x0005FFFF)) { + return 18; + } + if ((addr >=0x00060000) && (addr <= 0x00067FFF)) { + return 19; + } + if ((addr >=0x00068000) && (addr <= 0x0006FFFF)) { + return 20; + } + if ((addr >=0x00070000) && (addr <= 0x00077FFF)) { + return 21; + } + if ((addr >=0x00078000) && (addr <= 0x00078FFF)) { + return 22; + } + if ((addr >=0x00079000) && (addr <= 0x00079FFF)) { + return 23; + } + if ((addr >=0x0007A000) && (addr <= 0x0007AFFF)) { + return 24; + } + if ((addr >=0x0007B000) && (addr <= 0x0007BFFF)) { + return 25; + } + if ((addr >=0x0007C000) && (addr <= 0x0007CFFF)) { + return 26; + } + if ((addr >=0x0007D000) && (addr <= 0x0007DFFF)) { + return 27; + } + + /* no valid address within flash */ + return INVALID_ADDRESS; +} diff --git a/cpu/lpc2387/startup.s b/cpu/lpc2387/startup.s index f9ef062b4..057270f59 100644 --- a/cpu/lpc2387/startup.s +++ b/cpu/lpc2387/startup.s @@ -57,7 +57,7 @@ Undef_Addr: .word UNDEF_Routine /* defined in main.c */ SWI_Addr: .word ctx_switch /* defined in main.c */ PAbt_Addr: .word PABT_Routine /* defined in main.c */ DAbt_Addr: .word DABT_Routine /* defined in main.c */ -IRQ_Addr: .word fk_cpu_irq_isr /* defined in main.c */ +IRQ_Addr: .word arm_irq_handler /* defined in main.c */ /* Begin of boot code */ .text diff --git a/cpu/msp430/Jamfile b/cpu/msp430-common/Jamfile similarity index 95% rename from cpu/msp430/Jamfile rename to cpu/msp430-common/Jamfile index 9441b494e..19e40bb30 100644 --- a/cpu/msp430/Jamfile +++ b/cpu/msp430-common/Jamfile @@ -25,10 +25,10 @@ # ****************************************************************************** # $Id$ -SubDir TOP cpu msp430 ; +SubDir TOP cpu msp430-common ; Module cpu : msp430-main.c cpu.c atomic.c irq.c ; -Module hwtimer_cpu : hwtimer_cpu.c ; +Module hwtimer_msp430 : hwtimer_cpu.c ; UseModule cpu ; UseModule oneway_malloc ; diff --git a/cpu/msp430/Jamrules.msp430 b/cpu/msp430-common/Jamrules.msp430-common similarity index 82% rename from cpu/msp430/Jamrules.msp430 rename to cpu/msp430-common/Jamrules.msp430-common index 74d65de84..aaba8a424 100644 --- a/cpu/msp430/Jamrules.msp430 +++ b/cpu/msp430-common/Jamrules.msp430-common @@ -5,7 +5,7 @@ echo "Building for board $(BOARD)." ; echo "Building for MCU $(MCU)." ; -HDRS += $(TOP)/cpu/$(CPU)/include $(TOP)/board/$(BOARD)/drivers $(TOP)/board/$(BOARD)/include $(TOP)/include $(TOP)/core/include ; +HDRS += $(TOP)/cpu/msp430-common/include $(TOP)/cpu/$(CPU)/include $(TOP)/board/$(BOARD)/drivers $(TOP)/board/$(BOARD)/include $(TOP)/include $(TOP)/core/include ; TOOLCHAIN = msp430- ; CC = msp430-gcc ; diff --git a/cpu/msp430/atomic.c b/cpu/msp430-common/atomic.c similarity index 100% rename from cpu/msp430/atomic.c rename to cpu/msp430-common/atomic.c diff --git a/cpu/msp430/cpu.c b/cpu/msp430-common/cpu.c similarity index 87% rename from cpu/msp430/cpu.c rename to cpu/msp430-common/cpu.c index 1ea79aa33..1ffd72b78 100644 --- a/cpu/msp430/cpu.c +++ b/cpu/msp430-common/cpu.c @@ -28,25 +28,25 @@ and the mailinglist (subscription via web site) #include #include "kernel.h" #include "kernel_intern.h" -#include "scheduler.h" +#include "sched.h" volatile int __inISR = 0; char __isr_stack[MSP430_ISR_STACK_SIZE]; -void fk_yield() { +void thread_yield() { __save_context(); dINT(); - /* have fk_thread point to the next thread */ - fk_schedule(); + /* have active_thread point to the next thread */ + sched_run(); eINT(); __restore_context(); } // static void __resume_context () { -// __asm__("mov.w %0,r1" : : "m" (fk_thread->sp)); +// __asm__("mov.w %0,r1" : : "m" (active_thread->sp)); // // __asm__("pop r15"); // __asm__("pop r14"); @@ -81,15 +81,15 @@ void fk_yield() { // __asm__("push r14"); // __asm__("push r15"); // -// __asm__("mov.w r1,%0" : "=r" (fk_thread->sp)); +// __asm__("mov.w r1,%0" : "=r" (active_thread->sp)); // } // // // __return_from_isr -void fk_switch_context_exit(){ - fk_thread = fk_threads[0]; - fk_schedule(); +void cpu_switch_context_exit(){ + active_thread = sched_threads[0]; + sched_run(); __restore_context(); } @@ -97,12 +97,12 @@ void fk_switch_context_exit(){ //---------------------------------------------------------------------------- // Processor specific routine - here for MSP //---------------------------------------------------------------------------- -char *fk_stack_init(void *task_func, void *stack_start) +char *thread_stack_init(void *task_func, void *stack_start) { unsigned short * stk; stk = (unsigned short *) stack_start; - *stk = (unsigned short) fk_task_exit; + *stk = (unsigned short) sched_task_exit; --stk; *stk = (unsigned short) task_func; diff --git a/cpu/msp430-common/flashrom.c b/cpu/msp430-common/flashrom.c new file mode 100644 index 000000000..94d2e023f --- /dev/null +++ b/cpu/msp430-common/flashrom.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include + +uint8_t ie1, ie2; + +static uint8_t prepare(void); +static void finish(uint8_t istate); +static inline void busy_wait(void); + +/*---------------------------------------------------------------------------*/ +uint8_t flashrom_erase(uint8_t *addr) { + uint8_t istate = prepare(); + + FCTL3 = FWKEY; /* Lock = 0 */ + busy_wait(); + FCTL1 = FWKEY | ERASE; + *addr = 0; /* erase Flash segment */ + busy_wait(); + FCTL1 = FWKEY; /* ERASE = 0 */ + FCTL3 = FWKEY | LOCK; + finish(istate); + return 1; +} + +void flashrom_write(uint8_t *dst, uint8_t *src, size_t size) { + unsigned int i; + FCTL3 = FWKEY; /* Lock = 0 */ + busy_wait(); + for (i = size; i > 0; i--) { + FCTL1 = FWKEY | WRT; + *dst = *src; /* program Flash word */ + while (!(FCTL3 & WAIT)) { + nop(); + } + } + busy_wait(); + FCTL1 = FWKEY; /* WRT = 0 */ + FCTL3 = FWKEY | LOCK; /* Lock = 1 */ +} + +/*---------------------------------------------------------------------------*/ +static uint8_t prepare(void) { + uint8_t istate; + + /* Disable all interrupts. */ + + /* Clear interrupt flag1. */ + IFG1 = 0; + + /* DCO(SMCLK) is 2,4576MHz, /6 = 409600 Hz + select SMCLK for flash timing, divider 4+1 */ + FCTL2 = FWKEY | FSSEL_3 | FN2 | FN0; + + /* disable all interrupts to protect CPU + during programming from system crash */ + istate = disableIRQ(); + + /* disable all NMI-Interrupt sources */ + ie1 = IE1; + ie2 = IE2; + IE1 = 0x00; + IE2 = 0x00; + return istate; +} +/*---------------------------------------------------------------------------*/ +void finish(uint8_t istate) { + /* Enable interrupts. */ + IE1 = ie1; + IE2 = ie2; + restoreIRQ(istate); +} + +static inline void busy_wait(void) { + /* Wait for BUSY = 0, not needed unless run from RAM */ + while(FCTL3 & 0x0001) { + nop(); + } +} diff --git a/cpu/msp430/hwtimer_cpu.c b/cpu/msp430-common/hwtimer_cpu.c similarity index 70% rename from cpu/msp430/hwtimer_cpu.c rename to cpu/msp430-common/hwtimer_cpu.c index e25fd799e..ffb07fc32 100644 --- a/cpu/msp430/hwtimer_cpu.c +++ b/cpu/msp430-common/hwtimer_cpu.c @@ -31,31 +31,12 @@ and the mailinglist (subscription via web site) #include #include -#include "debug.h" +// #define ENABLE_DEBUG (1) +#include -static uint32_t ticks = 0; - -static void (*int_handler)(int); - -static void timerA_init() -{ - ticks = 0; // Set tick counter value to 0 - TA0CTL = TASSEL_1 + TACLR; // Clear the timer counter, set SMCLK - TA0CTL &= ~TAIFG; // Clear the IFG - TA0CTL &= ~TAIE; // Clear the IFG - - volatile unsigned int *ccr = &TA0CCR0; - volatile unsigned int *ctl = &TA0CCTL0; - - for (int i = 0; i < ARCH_MAXTIMERS; i++) { - *ccr = 0; - *ctl &= ~(CCIFG); - *ctl &= ~(CCIE); - } - - TA0CTL |= MC_2; -} +void (*int_handler)(int); +extern void timerA_init(void); static void TA0_disable_interrupt(short timer) { volatile unsigned int *ptr = &TA0CCTL0 + (timer); @@ -75,12 +56,12 @@ static void TA0_set_nostart(unsigned long value, short timer) { } static void TA0_set(unsigned long value, short timer) { -// printf("Setting timer %u to %lu\n", timer, value); + DEBUG("Setting timer %u to %lu\n", timer, value); TA0_set_nostart(value, timer); TA0_enable_interrupt(timer); } -static void TA0_unset(short timer) { +void TA0_unset(short timer) { volatile unsigned int *ptr = &TA0CCR0 + (timer); TA0_disable_interrupt(timer); *ptr = 0; @@ -119,33 +100,3 @@ void hwtimer_arch_set_absolute(unsigned long value, short timer) { void hwtimer_arch_unset(short timer) { TA0_unset(timer); } - -interrupt(TIMERA0_VECTOR) __attribute__ ((naked)) timer_isr_ccr0(void) -{ - __enter_isr(); - - TA0_unset(0); - int_handler(0); - - __exit_isr(); -} - -interrupt(TIMERA1_VECTOR) __attribute__ ((naked)) timer_isr(void) -{ - __enter_isr(); - - short taiv = TA0IV; - - if (taiv & TAIFG) { - puts("msp430/hwtimer_cpu TAIFG set!"); - // TA0CTL &= ~TAIFG; - // ticks += 0xFFFF; - } else { - - short timer = (taiv/2); - TA0_unset(timer); - int_handler(timer); - } - - __exit_isr(); -} diff --git a/cpu/msp430/include/cpu-conf.h b/cpu/msp430-common/include/cpu-conf.h similarity index 96% rename from cpu/msp430/include/cpu-conf.h rename to cpu/msp430-common/include/cpu-conf.h index 62958016e..a79e422f5 100644 --- a/cpu/msp430/include/cpu-conf.h +++ b/cpu/msp430-common/include/cpu-conf.h @@ -37,6 +37,9 @@ and the mailinglist (subscription via web site) #define KERNEL_CONF_STACKSIZE_IDLE 64 #define MSP430_ISR_STACK_SIZE 256 + +#define RX_BUF_SIZE (3) +#define TRANSCEIVER_BUFFER_SIZE (3) /** @} */ #endif /* CPUCONF_H_ */ diff --git a/cpu/msp430/include/cpu.h b/cpu/msp430-common/include/cpu.h similarity index 93% rename from cpu/msp430/include/cpu.h rename to cpu/msp430-common/include/cpu.h index 7a920aa05..e924cdff2 100644 --- a/cpu/msp430/include/cpu.h +++ b/cpu/msp430-common/include/cpu.h @@ -37,13 +37,14 @@ and the mailinglist (subscription via web site) * @{ */ -#include +#include #include #include #include #define WORDSIZE 16 +/* not used(?) */ #define F_CPU 10000000 extern volatile int __inISR; @@ -66,11 +67,11 @@ inline void __save_context_isr() { __asm__("push r5"); __asm__("push r4"); - __asm__("mov.w r1,%0" : "=r" (fk_thread->sp)); + __asm__("mov.w r1,%0" : "=r" (active_thread->sp)); } inline void __restore_context_isr() { - __asm__("mov.w %0,r1" : : "m" (fk_thread->sp)); + __asm__("mov.w %0,r1" : : "m" (active_thread->sp)); __asm__("pop r4"); __asm__("pop r5"); @@ -94,7 +95,7 @@ inline void __enter_isr() { inline void __exit_isr() { __inISR = 0; - if (fk_context_switch_request) fk_schedule(); + if (sched_context_switch_request) sched_run(); __restore_context_isr(); __asm__("reti"); } @@ -121,7 +122,7 @@ inline void dINT() { #define lpm_set(...) -void fk_yield(); +void thread_yield(); int inISR(); diff --git a/cpu/msp430/include/errno-base.h b/cpu/msp430-common/include/errno-base.h similarity index 100% rename from cpu/msp430/include/errno-base.h rename to cpu/msp430-common/include/errno-base.h diff --git a/cpu/msp430/include/errno.h b/cpu/msp430-common/include/errno.h similarity index 100% rename from cpu/msp430/include/errno.h rename to cpu/msp430-common/include/errno.h diff --git a/cpu/msp430/include/hwtimer_cpu.h b/cpu/msp430-common/include/hwtimer_cpu.h similarity index 98% rename from cpu/msp430/include/hwtimer_cpu.h rename to cpu/msp430-common/include/hwtimer_cpu.h index 1d014640c..e10ca6019 100644 --- a/cpu/msp430/include/hwtimer_cpu.h +++ b/cpu/msp430-common/include/hwtimer_cpu.h @@ -36,10 +36,10 @@ and the mailinglist (subscription via web site) #ifdef __MSP430_HAS_TA3__ #define ARCH_MAXTIMERS 3 #endif -/*#ifdef __MSP430_HAS_TA5__ +#ifdef __MSP430_HAS_T0A5__ #define ARCH_MAXTIMERS 5 #endif -*/ + #ifndef ARCH_MAXTIMERS #warning "ARCH_MAXTIMERS UNSET!" diff --git a/cpu/msp430/include/malloc.h b/cpu/msp430-common/include/malloc.h similarity index 100% rename from cpu/msp430/include/malloc.h rename to cpu/msp430-common/include/malloc.h diff --git a/cpu/msp430/include/msp430.h b/cpu/msp430-common/include/msp430.h similarity index 100% rename from cpu/msp430/include/msp430.h rename to cpu/msp430-common/include/msp430.h diff --git a/cpu/msp430-common/include/time.h b/cpu/msp430-common/include/time.h new file mode 100644 index 000000000..97bf471f4 --- /dev/null +++ b/cpu/msp430-common/include/time.h @@ -0,0 +1,15 @@ +#ifndef MSPGCC_TIME_H +#define MSPGCC_TIME_H + +struct tm +{ + int tm_sec; // Seconds after the minute [0, 59] + int tm_min; // Minutes after the hour [0, 59] + int tm_hour; // Hours since midnight [0, 23] + int tm_mday; // Day of the month [1, 31] + int tm_mon; // Months since January [0, 11] + int tm_year; // Years since 1900 + int tm_wday; // Days since Sunday [0, 6] +}; + +#endif diff --git a/cpu/msp430/irq.c b/cpu/msp430-common/irq.c similarity index 100% rename from cpu/msp430/irq.c rename to cpu/msp430-common/irq.c diff --git a/cpu/msp430/msp430-main.c b/cpu/msp430-common/msp430-main.c similarity index 100% rename from cpu/msp430/msp430-main.c rename to cpu/msp430-common/msp430-main.c diff --git a/cpu/msp430/startup.c b/cpu/msp430-common/startup.c similarity index 65% rename from cpu/msp430/startup.c rename to cpu/msp430-common/startup.c index d4a321913..8e04b9b97 100644 --- a/cpu/msp430/startup.c +++ b/cpu/msp430-common/startup.c @@ -1,6 +1,6 @@ #include -#include "board.h" -#include "kernel_intern.h" +#include +#include extern void board_init(); @@ -10,7 +10,7 @@ __attribute__ ((constructor)) static void startup() { board_init(); - puts("FireKernel MSP430 hardware initialization complete.\n"); + puts("ukleos MSP430 hardware initialization complete.\n"); kernel_init(); } diff --git a/cpu/msp430x16x/Jamfile b/cpu/msp430x16x/Jamfile new file mode 100644 index 000000000..14aa4df13 --- /dev/null +++ b/cpu/msp430x16x/Jamfile @@ -0,0 +1,33 @@ +# ****************************************************************************** +# Copyright 2010, Freie Universitaet Berlin (FUB). All rights reserved. +# +# These sources were developed at the Freie Universitaet Berlin, Computer +# Systems and Telematics group (http://cst.mi.fu-berlin.de). +# ------------------------------------------------------------------------------ +# This file is part of FeuerWare. +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# FeuerWare is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see http://www.gnu.org/licenses/ . +# ------------------------------------------------------------------------------ +# For further information and questions please use the web site +# http://scatterweb.mi.fu-berlin.de +# and the mailinglist (subscription via web site) +# scatterweb@lists.spline.inf.fu-berlin.de +# ****************************************************************************** +# $Id$ + +SubDir TOP cpu msp430x16x ; + +Module flashrom : flashrom.c ; +Module hwtimer_cpu : hwtimer_msp430.c : hwtimer_msp430 ; + +SubInclude TOP cpu msp430-common ; diff --git a/cpu/msp430x16x/Jamrules.msp430x16x b/cpu/msp430x16x/Jamrules.msp430x16x new file mode 100644 index 000000000..c66536fc9 --- /dev/null +++ b/cpu/msp430x16x/Jamrules.msp430x16x @@ -0,0 +1 @@ +include [ FPath $(TOP) cpu msp430-common Jamrules.msp430-common ] ; diff --git a/cpu/msp430x16x/flashrom.c b/cpu/msp430x16x/flashrom.c new file mode 100644 index 000000000..686e0cc3d --- /dev/null +++ b/cpu/msp430x16x/flashrom.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include + +uint8_t ie1, ie2; + +static uint8_t prepare(void); +static void finish(uint8_t istate); +static inline void busy_wait(void); + +/*---------------------------------------------------------------------------*/ +uint8_t flashrom_erase(uint8_t *addr) { + uint8_t istate = prepare(); + + FCTL3 = FWKEY; /* Lock = 0 */ + busy_wait(); + FCTL1 = FWKEY | ERASE; + *addr = 0; /* erase Flash segment */ + busy_wait(); + FCTL1 = FWKEY; /* ERASE = 0 */ + FCTL3 = FWKEY | LOCK; + finish(istate); + return 1; +} + +void flashrom_write(uint8_t *dst, uint8_t *src, size_t size) { + unsigned int i; + FCTL3 = FWKEY; /* Lock = 0 */ + busy_wait(); + for (i = size; i > 0; i--) { + FCTL1 = FWKEY | WRT; + *dst = *src; /* program Flash word */ + while (!(FCTL3 & WAIT)) { + nop(); + } + } + busy_wait(); + FCTL1 = FWKEY; /* WRT = 0 */ + FCTL3 = FWKEY | LOCK; /* Lock = 1 */ +} + +/*---------------------------------------------------------------------------*/ +static uint8_t prepare(void) { + uint8_t istate; + + /* Disable all interrupts. */ + + /* Clear interrupt flag1. */ + IFG1 = 0; + + /* DCO(SMCLK) is 2,4576MHz, /6 = 409600 Hz + select SMCLK for flash timing, divider 4+1 */ + FCTL2 = FWKEY | FSSEL_3 | FN2 | FN0; + + /* disable all interrupts to protect CPU + during programming from system crash */ + istate = disableIRQ(); + + /* disable all NMI-Interrupt sources */ + ie1 = IE1; + ie2 = IE2; + IE1 = 0x00; + IE2 = 0x00; + return istate; +} +/*---------------------------------------------------------------------------*/ +void finish(uint8_t istate) { + /* Enable interrupts. */ + IE1 = ie1; + IE2 = ie2; + restoreIRQ(istate); +} + +static inline void busy_wait(void) { + /* Wait for BUSY = 0, not needed unless run from RAM */ + while(FCTL3 & 0x0001) { + nop(); + } +} diff --git a/cpu/msp430x16x/hwtimer_msp430.c b/cpu/msp430x16x/hwtimer_msp430.c new file mode 100644 index 000000000..2a39a7ec8 --- /dev/null +++ b/cpu/msp430x16x/hwtimer_msp430.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include + +static uint32_t ticks = 0; + +extern void (*int_handler)(int); +extern void TA0_unset(short timer); + +void timerA_init() +{ + ticks = 0; // Set tick counter value to 0 + TA0CTL = TASSEL_1 + TACLR; // Clear the timer counter, set ACLK + TA0CTL &= ~TAIFG; // Clear the IFG + TA0CTL &= ~TAIE; // Clear the IFG + volatile unsigned int *ccr = &TA0CCR0; + volatile unsigned int *ctl = &TA0CCTL0; + + for (int i = 0; i < ARCH_MAXTIMERS; i++) { + *ccr = 0; + *ctl &= ~(CCIFG); + *ctl &= ~(CCIE); + } + TA0CTL |= MC_2; +} + +interrupt(TIMERA0_VECTOR) __attribute__ ((naked)) timer_isr_ccr0(void) { + __enter_isr(); + + TA0_unset(0); + int_handler(0); + + __exit_isr(); +} + +interrupt(TIMERA1_VECTOR) __attribute__ ((naked)) timer_isr(void) { + __enter_isr(); + + short taiv = TA0IV; + + if (taiv & TAIFG) { + // puts("msp430/hwtimer_cpu TAIFG set!"); + // TA0CTL &= ~TAIFG; + // ticks += 0xFFFF; + } else { + + short timer = (taiv/2); + TA0_unset(timer); + int_handler(timer); + } + + __exit_isr(); +} diff --git a/doc/doxygen/ukleos.doxyfile b/doc/doxygen/ukleos.doxyfile index bbf20122e..490fd04f2 100644 --- a/doc/doxygen/ukleos.doxyfile +++ b/doc/doxygen/ukleos.doxyfile @@ -85,7 +85,7 @@ WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- -INPUT = ../../core ../../cpu ../../board ../../sys ../manual +INPUT = ../../core ../../cpu ../../board ../../sys ../manual ../../drivers INPUT_ENCODING = UTF-8 FILE_PATTERNS = *.doc *.c *.h RECURSIVE = YES @@ -125,7 +125,7 @@ HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = src/ukleos-header.html HTML_FOOTER = src/ukleos-footer.html -HTML_STYLESHEET = src/ukleos.css +HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES HTML_DYNAMIC_SECTIONS = YES GENERATE_DOCSET = NO diff --git a/drivers/Jamfile b/drivers/Jamfile index e0223c05a..09eba8ba4 100644 --- a/drivers/Jamfile +++ b/drivers/Jamfile @@ -29,6 +29,9 @@ SubDir TOP drivers ; Module sht11 : sht11.c : hwtimer ; -Module ltc4150 : ltc4150.c : board_ltc4150 ; +Module ltc4150 : ltc4150.c : board_ltc4150 hwtimer ; + +Module vti_ps : vti_ps.c : vti_ps_twi ; SubInclude TOP drivers cc110x ; +SubInclude TOP drivers cc110x_ng ; diff --git a/drivers/cc110x/Jamfile b/drivers/cc110x/Jamfile index b96d897d9..528cef8d1 100755 --- a/drivers/cc110x/Jamfile +++ b/drivers/cc110x/Jamfile @@ -31,5 +31,5 @@ HDRS += $(TOP)/drivers/cc110x ; Module cc110x : cc1100.c cc1100-csmaca-mac.c cc1100-defaultSettings.c cc1100_phy.c cc1100_spi.c - : board_cc1100 swtimer protocol_multiplex gpioint ; + : board_cc110x swtimer protocol_multiplex gpioint ; diff --git a/drivers/cc110x/arch_cc1100.h b/drivers/cc110x/arch_cc1100.h index ef61dd61c..7c8b018a5 100644 --- a/drivers/cc110x/arch_cc1100.h +++ b/drivers/cc110x/arch_cc1100.h @@ -38,13 +38,13 @@ and the mailinglist (subscription via web site) #include -uint8_t cc1100_txrx(uint8_t c); +uint8_t cc110x_txrx(uint8_t c); -void cc1100_gdo0_enable(void); -void cc1100_gdo0_disable(void); -void cc1100_gdo2_enable(void); -void cc1100_gdo2_disable(void); -void cc1100_init_interrupts(void); +void cc110x_gdo0_enable(void); +void cc110x_gdo0_disable(void); +void cc110x_gdo2_enable(void); +void cc110x_gdo2_disable(void); +void cc110x_init_interrupts(void); -void cc1100_before_send(void); -void cc1100_after_send(void); +void cc110x_before_send(void); +void cc110x_after_send(void); diff --git a/drivers/cc110x/cc1100-csmaca-mac.c b/drivers/cc110x/cc1100-csmaca-mac.c index 077567a31..eed1f79bd 100644 --- a/drivers/cc110x/cc1100-csmaca-mac.c +++ b/drivers/cc110x/cc1100-csmaca-mac.c @@ -46,7 +46,7 @@ and the mailinglist (subscription via web site) #include #include -#include +#include "hwtimer.h" #include /*---------------------------------------------------------------------------*/ @@ -107,9 +107,9 @@ int cc1100_send_csmaca(radio_address_t address, protocol_t protocol, int priorit collisions_per_sec = 0; collision_state = COLLISION_STATE_MEASURE; } else if (collision_state == COLLISION_STATE_MEASURE) { - uint64_t timespan = swtimer_now() - collision_measurement_start; - if (timespan > 1000000) { - collisions_per_sec = (collision_count * 1000000) / (double) timespan; + uint64_t timespan = swtimer_now() - collision_measurement_start; + if (timespan > 1000000) { + collisions_per_sec = (collision_count * 1000000) / (double) timespan; if (collisions_per_sec > 0.5 && collisions_per_sec <= 2.2) { collision_measurement_start = swtimer_now(); collision_state = COLLISION_STATE_KEEP; @@ -121,8 +121,8 @@ int cc1100_send_csmaca(radio_address_t address, protocol_t protocol, int priorit } } } else if (collision_state == COLLISION_STATE_KEEP) { - uint64_t timespan = swtimer_now() - collision_measurement_start; - if (timespan > 5000000) { + uint64_t timespan = swtimer_now() - collision_measurement_start; + if (timespan > 5000000) { collision_state = COLLISION_STATE_INITIAL; } } diff --git a/drivers/cc110x/cc1100.c b/drivers/cc110x/cc1100.c index 5b671b3ad..7199694d2 100644 --- a/drivers/cc110x/cc1100.c +++ b/drivers/cc110x/cc1100.c @@ -160,19 +160,19 @@ volatile int wor_hwtimer_id = -1; void cc1100_disable_interrupts(void) { - cc1100_gdo2_disable(); - cc1100_gdo0_disable(); + cc110x_gdo2_disable(); + cc110x_gdo0_disable(); } -void cc1100_gdo0_irq(void) +void cc110x_gdo0_irq(void) { // Air was not free -> Clear CCA flag rflags.CAA = false; // Disable carrier sense detection (GDO0 interrupt) - cc1100_gdo0_disable(); + cc110x_gdo0_disable(); } -void cc1100_gdo2_irq(void) +void cc110x_gdo2_irq(void) { cc1100_phy_rx_handler(); } @@ -251,9 +251,9 @@ bool cc1100_spi_receive_packet(uint8_t *rxBuffer, uint8_t length) void cc1100_set_idle(void) { if (radio_state == RADIO_WOR) { // Wake up the chip from WOR/sleep - cc1100_spi_select(); + cc110x_spi_select(); hwtimer_wait(RTIMER_TICKS(122)); - cc1100_spi_unselect(); + cc110x_spi_unselect(); radio_state = RADIO_IDLE; // XOSC startup + FS calibration (300 + 809 us ~ 1.38 ms) hwtimer_wait(FS_CAL_TIME); @@ -292,9 +292,9 @@ static void wakeup_from_wor(void) return; } // Wake up the chip from WOR/sleep - cc1100_spi_select(); + cc110x_spi_select(); hwtimer_wait(RTIMER_TICKS(122)); - cc1100_spi_unselect(); + cc110x_spi_unselect(); radio_state = RADIO_IDLE; // XOSC startup + FS calibration (300 + 809 us ~ 1.38 ms) hwtimer_wait(FS_CAL_TIME); @@ -305,7 +305,7 @@ static void wakeup_from_wor(void) */ void switch_to_wor2(void) { - if (cc1100_get_gdo2()) return; // If incoming packet, then don't go to WOR now + if (cc110x_get_gdo2()) return; // If incoming packet, then don't go to WOR now cc1100_spi_strobe(CC1100_SIDLE); // Put CC1100 to IDLE radio_state = RADIO_IDLE; // Radio state now IDLE cc1100_spi_write_reg(CC1100_MCSM2, @@ -336,7 +336,7 @@ static void hwtimer_switch_to_wor2_wrapper(void* ptr) static void switch_to_wor(void) { // Any incoming packet? - if (cc1100_get_gdo2()) + if (cc110x_get_gdo2()) { // Then don't go to WOR now return; @@ -558,16 +558,16 @@ void cc1100_hwtimer_go_receive_wrapper(void *ptr) static void reset(void) { cc1100_go_idle(); - cc1100_spi_select(); + cc110x_spi_select(); cc1100_spi_strobe(CC1100_SRES); hwtimer_wait(RTIMER_TICKS(10)); } static void power_up_reset(void) { - cc1100_spi_unselect(); - cc1100_spi_cs(); - cc1100_spi_unselect(); + cc110x_spi_unselect(); + cc110x_spi_cs(); + cc110x_spi_unselect(); hwtimer_wait(RESET_WAIT_TIME); reset(); radio_state = RADIO_IDLE; @@ -587,7 +587,7 @@ void cc1100_send_raw(uint8_t *tx_buffer, uint8_t size) if (size > PACKET_LENGTH) return; // Disables RX interrupt etc. - cc1100_before_send(); + cc110x_before_send(); // But CC1100 in IDLE mode to flush the FIFO cc1100_spi_strobe(CC1100_SIDLE); @@ -600,7 +600,7 @@ void cc1100_send_raw(uint8_t *tx_buffer, uint8_t size) unsigned int cpsr = disableIRQ(); cc1100_spi_strobe(CC1100_STX); // Wait for GDO2 to be set -> sync word transmitted - while (cc1100_get_gdo2() == 0) { + while (cc110x_get_gdo2() == 0) { abort_count++; if (abort_count > CC1100_SYNC_WORD_TX_TIME) { // Abort waiting. CC1100 maybe in wrong mode @@ -611,9 +611,9 @@ void cc1100_send_raw(uint8_t *tx_buffer, uint8_t size) } restoreIRQ(cpsr); // Wait for GDO2 to be cleared -> end of packet - while (cc1100_get_gdo2() != 0); + while (cc110x_get_gdo2() != 0); // Experimental - TOF Measurement - cc1100_after_send(); + cc110x_after_send(); } /*---------------------------------------------------------------------------*/ @@ -742,7 +742,7 @@ rssi_2_dbm(uint8_t rssi) void cc1100_init(void) { // Initialize SPI - cc1100_spi_init(); + cc110x_spi_init(); // Set default mode (with default (energy optimized) RX interval) cc1100_set_mode0(CC1100_RADIO_MODE, T_RX_INTERVAL); @@ -834,7 +834,7 @@ rd_set_mode(int mode) switch (mode) { case RADIO_MODE_ON: - cc1100_init_interrupts(); // Enable interrupts + cc110x_init_interrupts(); // Enable interrupts cc1100_setup_mode(); // Set chip to desired mode break; case RADIO_MODE_OFF: @@ -877,19 +877,19 @@ void cc1100_cs_set_enabled(bool enabled) if (enabled) { // Enable carrier sense detection (GDO0 interrupt) - cc1100_gdo0_enable(); + cc110x_gdo0_enable(); } else { // Disable carrier sense detection (GDO0 interrupt) - cc1100_gdo0_disable(); + cc110x_gdo0_disable(); } } int cc1100_cs_read(void) { /* GDO0 reflects CS (high: air not free, low: air free) */ - return cc1100_get_gdo0(); + return cc110x_get_gdo0(); } int cc1100_cs_read_cca(void) diff --git a/drivers/cc110x/cc1100_phy.c b/drivers/cc110x/cc1100_phy.c index 036792ee2..acc374761 100644 --- a/drivers/cc110x/cc1100_phy.c +++ b/drivers/cc110x/cc1100_phy.c @@ -45,7 +45,7 @@ and the mailinglist (subscription via web site) #include #include "hwtimer.h" -#include "swtimer.h" +#include #include "cc1100.h" #include "cc1100_spi.h" @@ -60,6 +60,8 @@ and the mailinglist (subscription via web site) #include "msg.h" #include "debug.h" +#define PRIORITY_CC1100 PRIORITY_MAIN-1 + #define MSG_POLL 12346 #define FLAGS_IDENTIFICATION (0x01) ///< Bit mask for reading the identification out of the flags field @@ -94,10 +96,13 @@ static const pm_table_t handler_table; static const char *cc1100_event_handler_name = "cc1100_event_handler"; static mutex_t cc1100_mutex; volatile int cc1100_mutex_pid; +static swtimer_t cc1100_watch_dog; +static swtime_t cc1100_watch_dog_period = 0; + static uint16_t cc1100_event_handler_pid; static void cc1100_event_handler_function(void); -static swtimer_t cc1100_watch_dog; -static uint64_t cc1100_watch_dog_period = 0; + +static char event_handler_stack[KERNEL_CONF_STACKSIZE_MAIN]; /*---------------------------------------------------------------------------*/ // Sequence number buffer management data structures @@ -114,10 +119,10 @@ typedef struct uint64_t m_ticks; ///< 64-bit timestamp uint8_t source; ///< Source address uint8_t identification; ///< Identification (1-bit) -} seq_buffer_entry; +} seq_buffer_entry_t; /// Sequence number buffer for this layer -static seq_buffer_entry seq_buffer[MAX_SEQ_BUFFER_SIZE]; +static seq_buffer_entry_t seq_buffer[MAX_SEQ_BUFFER_SIZE]; /// Next position to enter a new value into ::seqBuffer static uint8_t seq_buffer_pos = 0; @@ -181,14 +186,14 @@ void cc1100_phy_init() pm_init_table((pm_table_t*)&handler_table, MAX_PACKET_HANDLERS, handlers); // Clear sequence number buffer - memset(seq_buffer, 0, sizeof(seq_buffer_entry) * MAX_SEQ_BUFFER_SIZE); + memset(seq_buffer, 0, sizeof(seq_buffer_entry_t) * MAX_SEQ_BUFFER_SIZE); // Initialize mutex cc1100_mutex_pid = -1; mutex_init(&cc1100_mutex); // Allocate event numbers and start cc1100 event process - cc1100_event_handler_pid = thread_create(2500, PRIORITY_CC1100, CREATE_STACKTEST, + cc1100_event_handler_pid = thread_create(event_handler_stack, sizeof(event_handler_stack), PRIORITY_CC1100, CREATE_STACKTEST, cc1100_event_handler_function, cc1100_event_handler_name); // Active watchdog for the first time @@ -206,9 +211,9 @@ void cc1100_phy_init() void cc1100_phy_mutex_lock(void) { - if (fk_thread->pid != cc1100_mutex_pid) { + if (active_thread->pid != cc1100_mutex_pid) { mutex_lock(&cc1100_mutex); - cc1100_mutex_pid = fk_thread->pid; + cc1100_mutex_pid = active_thread->pid; } } @@ -377,7 +382,7 @@ static bool contains_seq_entry(uint8_t src, uint8_t id) { // Check if time stamp is OK cmp = (radio_mode == CC1100_MODE_WOR) ? cc1100_wor_config.rx_interval : 16000; // constant RX ~16ms - if ((now - seq_buffer[i].m_ticks) <= cmp) + if ((now - seq_buffer[i].m_ticks) <= cmp) { return true; } @@ -407,7 +412,7 @@ static void add_seq_entry(uint8_t src, uint8_t id) // Add new entry seq_buffer[seq_buffer_pos].source = src; seq_buffer[seq_buffer_pos].identification = id; - seq_buffer[seq_buffer_pos].m_ticks = swtimer_now(); + seq_buffer[seq_buffer_pos].m_ticks = swtimer_now(); // Store 16 bit sequence number of layer 0 for speedup last_seq_num = src; @@ -619,7 +624,8 @@ int cc1100_set_packet_handler(protocol_t protocol, packet_handler_t handler) static void cc1100_event_handler_function(void) { - msg m; + msg_t m; + while (1) { if (cc1100_watch_dog_period != 0) { @@ -680,7 +686,7 @@ static void cc1100_event_handler_function(void) void cc1100_phy_rx_handler(void) { - msg m; + msg_t m; m.type = MSG_POLL; bool dup = false; bool res = false; diff --git a/drivers/cc110x/cc1100_spi.c b/drivers/cc110x/cc1100_spi.c index ef5206cb6..2614caf20 100644 --- a/drivers/cc110x/cc1100_spi.c +++ b/drivers/cc110x/cc1100_spi.c @@ -61,13 +61,13 @@ cc1100_spi_writeburst_reg(uint8_t addr, char *src, uint8_t count) { int i = 0; unsigned int cpsr = disableIRQ(); - cc1100_spi_select(); - cc1100_txrx(addr | CC1100_WRITE_BURST); + cc110x_spi_select(); + cc110x_txrx(addr | CC1100_WRITE_BURST); while (i < count) { - cc1100_txrx(src[i]); + cc110x_txrx(src[i]); i++; } - cc1100_spi_unselect(); + cc110x_spi_unselect(); restoreIRQ(cpsr); return count; } @@ -77,13 +77,13 @@ cc1100_spi_readburst_reg(uint8_t addr, char *buffer, uint8_t count) { int i = 0; unsigned int cpsr = disableIRQ(); - cc1100_spi_select(); - cc1100_txrx(addr | CC1100_READ_BURST); + cc110x_spi_select(); + cc110x_txrx(addr | CC1100_READ_BURST); while (i < count) { - buffer[i] = cc1100_txrx(NOBYTE); + buffer[i] = cc110x_txrx(NOBYTE); i++; } - cc1100_spi_unselect(); + cc110x_spi_unselect(); restoreIRQ(cpsr); } @@ -91,10 +91,10 @@ void cc1100_spi_write_reg(uint8_t addr, uint8_t value) { unsigned int cpsr = disableIRQ(); - cc1100_spi_select(); - cc1100_txrx(addr); - cc1100_txrx(value); - cc1100_spi_unselect(); + cc110x_spi_select(); + cc110x_txrx(addr); + cc110x_txrx(value); + cc110x_spi_unselect(); restoreIRQ(cpsr); } @@ -102,10 +102,10 @@ uint8_t cc1100_spi_read_reg(uint8_t addr) { uint8_t result; unsigned int cpsr = disableIRQ(); - cc1100_spi_select(); - cc1100_txrx(addr | CC1100_READ_SINGLE); - result = cc1100_txrx(NOBYTE); - cc1100_spi_unselect(); + cc110x_spi_select(); + cc110x_txrx(addr | CC1100_READ_SINGLE); + result = cc110x_txrx(NOBYTE); + cc110x_spi_unselect(); restoreIRQ(cpsr); return result; } @@ -114,10 +114,10 @@ uint8_t cc1100_spi_read_status(uint8_t addr) { uint8_t result; unsigned int cpsr = disableIRQ(); - cc1100_spi_select(); - cc1100_txrx(addr | CC1100_READ_BURST); - result = cc1100_txrx(NOBYTE); - cc1100_spi_unselect(); + cc110x_spi_select(); + cc110x_txrx(addr | CC1100_READ_BURST); + result = cc110x_txrx(NOBYTE); + cc110x_spi_unselect(); restoreIRQ(cpsr); return result; } @@ -126,9 +126,9 @@ uint8_t cc1100_spi_strobe(uint8_t c) { uint8_t result; unsigned int cpsr = disableIRQ(); - cc1100_spi_select(); - result = cc1100_txrx(c); - cc1100_spi_unselect(); + cc110x_spi_select(); + result = cc110x_txrx(c); + cc110x_spi_unselect(); restoreIRQ(cpsr); return result; } diff --git a/drivers/cc110x/cc1100_spi.h b/drivers/cc110x/cc1100_spi.h index 736f98218..e76deb8b2 100644 --- a/drivers/cc110x/cc1100_spi.h +++ b/drivers/cc110x/cc1100_spi.h @@ -44,14 +44,14 @@ and the mailinglist (subscription via web site) #ifndef CC1100_SPI_H_ #define CC1100_SPI_H_ -int cc1100_get_gdo0(void); -int cc1100_get_gdo1(void); -int cc1100_get_gdo2(void); +int cc110x_get_gdo0(void); +int cc110x_get_gdo1(void); +int cc110x_get_gdo2(void); -void cc1100_spi_init(void); -void cc1100_spi_cs(void); -void cc1100_spi_select(void); -void cc1100_spi_unselect(void); +void cc110x_spi_init(void); +void cc110x_spi_cs(void); +void cc110x_spi_select(void); +void cc110x_spi_unselect(void); uint8_t cc1100_spi_writeburst_reg(uint8_t addr, char *buffer, uint8_t count); void cc1100_spi_readburst_reg(uint8_t addr, char *buffer, uint8_t count); diff --git a/drivers/cc110x_ng/Jamfile b/drivers/cc110x_ng/Jamfile new file mode 100755 index 000000000..b47dfc890 --- /dev/null +++ b/drivers/cc110x_ng/Jamfile @@ -0,0 +1,34 @@ +# ****************************************************************************** +# Copyright 2010, Freie Universitaet Berlin (FUB). All rights reserved. +# +# These sources were developed at the Freie Universitaet Berlin, Computer +# Systems and Telematics group (http://cst.mi.fu-berlin.de). +# ------------------------------------------------------------------------------ +# This file is part of µkleos. +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# FeuerWare is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see http://www.gnu.org/licenses/ . +# ------------------------------------------------------------------------------ +# For further information and questions please use the web site +# http://scatterweb.mi.fu-berlin.de +# and the mailinglist (subscription via web site) +# scatterweb@lists.spline.inf.fu-berlin.de +# ****************************************************************************** +# $Id: Jamfile 832 2009-03-13 16:45:41Z kaspar $ + +SubDir TOP drivers cc110x_ng ; + +HDRS += $(TOP)/drivers/cc110x_ng/include ; + +Module cc110x_ng : cc110x.c cc110x-rx.c cc110x-tx.c cc110x-defaultSettings.c : hwtimer board_cc110x ; +Module cc110x_spi : cc110x_spi.c ; +Module cc110x_cc430 : cc110x_cc430.c ; diff --git a/drivers/cc110x_ng/cc110x-defaultSettings.c b/drivers/cc110x_ng/cc110x-defaultSettings.c new file mode 100644 index 000000000..dc15fbd23 --- /dev/null +++ b/drivers/cc110x_ng/cc110x-defaultSettings.c @@ -0,0 +1,141 @@ +/****************************************************************************** +Copyright 2008, Freie Universitaet Berlin (FUB). All rights reserved. + +These sources were developed at the Freie Universitaet Berlin, Computer Systems +and Telematics group (http://cst.mi.fu-berlin.de). +------------------------------------------------------------------------------- +This file is part of FeuerWare. + +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +FeuerWare is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see http://www.gnu.org/licenses/ . +-------------------------------------------------------------------------------- +For further information and questions please use the web site + http://scatterweb.mi.fu-berlin.de +and the mailinglist (subscription via web site) + scatterweb@lists.spline.inf.fu-berlin.de +*******************************************************************************/ + +/** + * @ingroup dev_cc110x + * @{ + */ + +/** + * @file + * @brief TI Chipcon CC110x default settings + * + * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project + * @author Thomas Hillebrandt + * @author Heiko Will + * @version $Revision: 2058 $ + * + * @note $Id: cc110x-defaultSettings.c 2058 2010-03-31 08:59:31Z hillebra $ + */ + +#include + +/** + * Usable, non overlapping channels and corresponding frequencies + * for use with CC1100. CHANNR is the register for selecting a channel. + * + * channel number | CHANNR | frequency [MHz] + * ----------------------------------------- + * 0 | 0 | 869.525 + * 1 | 10 | 871.61 + * 2 | 20 | 873.58 ~ seems to be bad (hang-ups with this channel) + * 3 | 30 | 875.61 + * 4 | 40 | 877.58 + * 5 | 50 | 879.61 + * 6 | 60 | 881.58 + * 7 | 70 | 883.61 + * 8 | 80 | 885.58 + * 9 | 90 | 887.61 + * 10 | 100 | 889.58 + * 11 | 110 | 891.57 + * 12 | 120 | 893.58 + * 13 | 130 | 895.61 + * 14 | 140 | 897.58 + * 15 | 150 | 899.57 + * 16 | 160 | 901.57 + * 17 | 170 | 903.61 + * 18 | 180 | 905.57 + * 19 | 190 | 907.57 + * 20 | 200 | 909.57 + * 21 | 210 | 911.57 + * 22 | 220 | 913.57 + * 23 | 230 | 915.61 + * 24 | 240 | 917.61 + */ + +// 400 kbps, MSK, X-tal: 26 MHz (Chip Revision F) +char cc110x_conf[] = { + 0x06, // IOCFG2 + 0x2E, // IOCFG1 + 0x0E, // IOCFG0 + 0x0F, // FIFOTHR + 0x9B, // SYNC1 + 0xAD, // SYNC0 + 0x3D, // PKTLEN (maximum value of packet length byte = 61) + 0x06, // PKTCTRL1 + 0x45, // PKTCTRL0 (variable packet length) + 0xFF, // ADDR + CC1100_DEFAULT_CHANNR*10, // CHANNR + 0x0B, // FSCTRL1 + 0x00, // FSCTRL0 + 0x21, // FREQ2 + 0x71, // FREQ1 + 0x7A, // FREQ0 + 0x2D, // MDMCFG4 + 0xF8, // MDMCFG3 + 0x73, // MDMCFG2 + 0x42, // MDMCFG1 + 0xF8, // MDMCFG0 + 0x00, // DEVIATN + 0x07, // MCSM2 + 0x03, // MCSM1 + 0x18, // MCSM0 + 0x1D, // FOCCFG + 0x1C, // BSCFG + 0xC0, // AGCCTRL2 + 0x49, // AGCCTRL1, (old value was 0x49 -> made carrier sense less sensitive!) + // 0x47 - 7 dB above MAGN_TARGET setting + 0xB2, // AGCCTRL0 + 0x87, // WOREVT1 + 0x6B, // WOREVT0 + 0xF8, // WORCTRL + 0xB6, // FREND1 + 0x10, // FREND0 + 0xEA, // FSCAL3 + 0x2A, // FSCAL2 + 0x00, // FSCAL1 + 0x1F, // FSCAL0 + 0x00 // padding to 4 bytes +}; + +uint8_t pa_table_index = PATABLE; ///< Current PATABLE Index +uint8_t pa_table[] = { ///< PATABLE with available output powers + 0x00, ///< -52 dBm + 0x03, ///< -30 dBm + 0x0D, ///< -20 dBm + 0x1C, ///< -15 dBm + 0x34, ///< -10 dBm + 0x57, ///< - 5 dBm + 0x3F, ///< - 1 dBm + 0x8E, ///< 0 dBm + 0x85, ///< + 5 dBm + 0xCC, ///< + 7 dBm + 0xC6, ///< + 9 dBm + 0xC3 ///< +10 dBm +}; // If PATABLE is changed in size, adjust MAX_OUTPUT_POWER definition in CC1100 interface! + + +/** @} */ diff --git a/drivers/cc110x_ng/cc110x-rx.c b/drivers/cc110x_ng/cc110x-rx.c new file mode 100644 index 000000000..3a5e5ba9a --- /dev/null +++ b/drivers/cc110x_ng/cc110x-rx.c @@ -0,0 +1,158 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +static uint8_t receive_packet_variable(uint8_t *rxBuffer, uint8_t length); +static uint8_t receive_packet(uint8_t *rxBuffer, uint8_t length); + +rx_buffer_t cc110x_rx_buffer[RX_BUF_SIZE]; ///< RX buffer +volatile uint8_t rx_buffer_next; ///< Next packet in RX queue + +void cc110x_rx_handler(void) { + uint8_t res = 0; + + // Possible packet received, RX -> IDLE (0.1 us) + rflags.CAA = 0; + rflags.MAN_WOR = 0; + cc110x_statistic.packets_in++; + + res = receive_packet((uint8_t*)&(cc110x_rx_buffer[rx_buffer_next].packet), sizeof(cc110x_packet_t)); + if (res) { + // If we are sending a burst, don't accept packets. + // Only ACKs are processed (for stopping the burst). + // Same if state machine is in TX lock. + if (radio_state == RADIO_SEND_BURST || rflags.TX) + { + cc110x_statistic.packets_in_while_tx++; + return; + } + cc110x_rx_buffer[rx_buffer_next].rssi = rflags._RSSI; + cc110x_rx_buffer[rx_buffer_next].lqi = rflags._LQI; + cc110x_strobe(CC1100_SFRX); // ...for flushing the RX FIFO + + // Valid packet. After a wake-up, the radio should be in IDLE. + // So put CC1100 to RX for WOR_TIMEOUT (have to manually put + // the radio back to sleep/WOR). + //cc110x_spi_write_reg(CC1100_MCSM0, 0x08); // Turn off FS-Autocal + cc110x_write_reg(CC1100_MCSM2, 0x07); // Configure RX_TIME (until end of packet) + cc110x_strobe(CC1100_SRX); + hwtimer_wait(IDLE_TO_RX_TIME); + radio_state = RADIO_RX; + + /* notify transceiver thread if any */ + if (transceiver_pid) { + msg_t m; + m.type = (uint16_t) RCV_PKT_CC1100; + m.content.value = rx_buffer_next; + msg_send_int(&m, transceiver_pid); + } + + /* shift to next buffer element */ + if (++rx_buffer_next == RX_BUF_SIZE) { + rx_buffer_next = 0; + } + return; + } + else + { + // No ACK received so TOF is unpredictable + rflags.TOF = 0; + + // CRC false or RX buffer full -> clear RX FIFO in both cases + cc110x_strobe(CC1100_SIDLE); // Switch to IDLE (should already be)... + cc110x_strobe(CC1100_SFRX); // ...for flushing the RX FIFO + + // If packet interrupted this nodes send call, + // don't change anything after this point. + if (radio_state == RADIO_AIR_FREE_WAITING) + { + cc110x_strobe(CC1100_SRX); + hwtimer_wait(IDLE_TO_RX_TIME); + return; + } + // If currently sending, exit here (don't go to RX/WOR) + if (radio_state == RADIO_SEND_BURST) + { + cc110x_statistic.packets_in_while_tx++; + return; + } + + // No valid packet, so go back to RX/WOR as soon as possible + cc110x_switch_to_rx(); + } +} + + +static uint8_t receive_packet_variable(uint8_t *rxBuffer, uint8_t length) { + uint8_t status[2]; + uint8_t packetLength = 0; + + /* Any bytes available in RX FIFO? */ + if ((cc110x_read_status(CC1100_RXBYTES) & BYTES_IN_RXFIFO)) { + //LED_GREEN_TOGGLE; + //LED_RED_TOGGLE; + // Read length byte (first byte in RX FIFO) + cc110x_read_fifo((char*) &packetLength, 1); + // Read data from RX FIFO and store in rxBuffer + if (packetLength <= length) + { + // Put length byte at first position in RX Buffer + rxBuffer[0] = packetLength; + + // Read the rest of the packet + //cc110x_readburst_reg(CC1100_RXFIFO, (char*)rxBuffer+1, packetLength); + cc110x_read_fifo((char*) rxBuffer + 1, packetLength); + + // Read the 2 appended status bytes (status[0] = RSSI, status[1] = LQI) + cc110x_readburst_reg(CC1100_RXFIFO, (char*)status, 2); + + // Store RSSI value of packet + rflags._RSSI = status[I_RSSI]; + + // MSB of LQI is the CRC_OK bit + rflags.CRC = (status[I_LQI] & CRC_OK) >> 7; + if (!rflags.CRC) { + cc110x_statistic.packets_in_crc_fail++; + } + + // Bit 0-6 of LQI indicates the link quality (LQI) + rflags._LQI = status[I_LQI] & LQI_EST; + + return rflags.CRC; + } + /* too many bytes in FIFO */ + else { + // RX FIFO get automatically flushed if return value is false + return 0; + } + } + /* no bytes in RX FIFO */ + else { + //LED_RED_TOGGLE; + // RX FIFO get automatically flushed if return value is false + return 0; + } +} + +static uint8_t receive_packet(uint8_t *rxBuffer, uint8_t length) { + uint8_t pkt_len_cfg = cc110x_read_reg(CC1100_PKTCTRL0) & PKT_LENGTH_CONFIG; + if (pkt_len_cfg == VARIABLE_PKTLEN) + { + return receive_packet_variable(rxBuffer, length); + } + // Fixed packet length not supported. + // RX FIFO get automatically flushed if return value is false + return 0; +} + + diff --git a/drivers/cc110x_ng/cc110x-tx.c b/drivers/cc110x_ng/cc110x-tx.c new file mode 100644 index 000000000..bffb8339d --- /dev/null +++ b/drivers/cc110x_ng/cc110x-tx.c @@ -0,0 +1,78 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +uint8_t cc110x_send(cc110x_packet_t *packet) { + volatile uint32_t abort_count; + uint8_t size; + /* TODO: burst sending */ + radio_state = RADIO_SEND_BURST; + rflags.LL_ACK = 0; + + /* + * Number of bytes to send is: + * length of phy payload (packet->length) + * + size of length field (1 byte) + */ + size = packet->length + 1; + + // The number of bytes to be transmitted must be smaller + // or equal to PACKET_LENGTH (62 bytes). So the receiver + // can put the whole packet in its RX-FIFO (with appended + // packet status bytes). + if (size > PACKET_LENGTH) { + return 0; + } + + packet->phy_src = cc110x_get_address(); + + // Disables RX interrupt etc. + cc110x_before_send(); + + // But CC1100 in IDLE mode to flush the FIFO + cc110x_strobe(CC1100_SIDLE); + // Flush TX FIFO to be sure it is empty + cc110x_strobe(CC1100_SFTX); + // Write packet into TX FIFO + cc110x_writeburst_reg(CC1100_TXFIFO, (char*) packet, size); + // Switch to TX mode + abort_count = 0; + unsigned int cpsr = disableIRQ(); + cc110x_strobe(CC1100_STX); + // Wait for GDO2 to be set -> sync word transmitted + while (cc110x_get_gdo2() == 0) { + abort_count++; + if (abort_count > CC1100_SYNC_WORD_TX_TIME) { + // Abort waiting. CC1100 maybe in wrong mode + // e.g. sending preambles for always + puts("[CC1100 TX] fatal error\n"); + break; + } + } + restoreIRQ(cpsr); + // Wait for GDO2 to be cleared -> end of packet + while (cc110x_get_gdo2() != 0); + //LED_GREEN_TOGGLE; + + // Experimental - TOF Measurement + cc110x_after_send(); + cc110x_statistic.raw_packets_out++; + + // Store number of transmission retries + rflags.TX = 0; + + // Go to mode after TX (CONST_RX -> RX, WOR -> WOR) + cc110x_switch_to_rx(); + + return true; +} + diff --git a/drivers/cc110x_ng/cc110x.c b/drivers/cc110x_ng/cc110x.c new file mode 100644 index 000000000..243c3c411 --- /dev/null +++ b/drivers/cc110x_ng/cc110x.c @@ -0,0 +1,336 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +//#define ENABLE_DEBUG (1) +#include + +/* some externals */ +extern uint8_t pa_table[]; ///< PATABLE with available output powers +extern uint8_t pa_table_index; ///< Current PATABLE Index + +/* global variables */ + +cc110x_statistic_t cc110x_statistic; + +volatile cc110x_flags rflags; ///< Radio control flags +volatile uint8_t radio_state = RADIO_UNKNOWN; ///< Radio state + +static radio_address_t radio_address; ///< Radio address +static uint8_t radio_channel; ///< Radio channel + +int transceiver_pid; ///< the transceiver thread pid + +/* internal function prototypes */ +static int rd_set_mode(int mode); +static void reset(void); +static void power_up_reset(void); +static void write_register(uint8_t r, uint8_t value); + +/*---------------------------------------------------------------------------*/ +// Radio Driver API +/*---------------------------------------------------------------------------*/ +void cc110x_init(int tpid) { + transceiver_pid = tpid; + DEBUG("Transceiver PID: %i\n", transceiver_pid); + + rx_buffer_next = 0; + +#ifdef MODULE_CC110X_SPI + /* Initialize SPI */ + cc110x_spi_init(); +#endif + + /* Load driver & reset */ + power_up_reset(); + + /* Write configuration to configuration registers */ + cc110x_writeburst_reg(0x00, cc110x_conf, CC1100_CONF_SIZE); + + /* Write PATABLE (power settings) */ + cc110x_write_reg(CC1100_PATABLE, pa_table[pa_table_index]); + + /* Initialize Radio Flags */ + rflags._RSSI = 0x00; + rflags.LL_ACK = 0; + rflags.CAA = 0; + rflags.CRC = 0; + rflags.SEQ = 0; + rflags.MAN_WOR = 0; + rflags.KT_RES_ERR = 0; + rflags.TX = 0; + rflags.WOR_RST = 0; + + /* Set default channel number */ +#ifdef MODULE_CONFIG + cc110x_set_config_channel(sysconfig.radio_channel); +#else + cc110x_set_channel(CC1100_DEFAULT_CHANNR); +#endif + DEBUG("CC1100 initialized and set to channel %i\n", radio_channel); + + // Switch to desired mode (WOR or RX) + rd_set_mode(RADIO_MODE_ON); +} + +void cc110x_disable_interrupts(void) { + cc110x_gdo2_disable(); + cc110x_gdo0_disable(); +} + +void cc110x_gdo0_irq(void) { + // Air was not free -> Clear CCA flag + rflags.CAA = false; + // Disable carrier sense detection (GDO0 interrupt) + cc110x_gdo0_disable(); +} + +void cc110x_gdo2_irq(void) { + cc110x_rx_handler(); +} + +uint8_t cc110x_get_buffer_pos(void) { + return (rx_buffer_next-1); +} + +radio_address_t cc110x_get_address() { + return radio_address; +} + +radio_address_t cc110x_set_address(radio_address_t address) { + if ((address < MIN_UID) || (address > MAX_UID)) { + return 0; + } + + uint8_t id = (uint8_t) address; + if (radio_state != RADIO_UNKNOWN) { + write_register(CC1100_ADDR, id); + } + + radio_address = id; + return radio_address; +} + +#ifdef MODULE_CONFIG +radio_address_t cc110x_set_config_address(radio_address_t address) { + radio_address_t a = cc110x_set_address(address); + if (a) { + sysconfig.radio_address = a; + } + config_save(); + return a; +} +#endif + +void cc110x_set_monitor(uint8_t mode) { + if (mode) { + write_register(CC1100_PKTCTRL1, (0x04)); + } + else { + write_register(CC1100_PKTCTRL1, (0x06)); + } +} + +void cc110x_setup_rx_mode(void) { + // Stay in RX mode until end of packet + cc110x_write_reg(CC1100_MCSM2, 0x07); + cc110x_switch_to_rx(); +} + +void cc110x_switch_to_rx(void) { + radio_state = RADIO_RX; + cc110x_strobe(CC1100_SRX); +} + +void cc110x_wakeup_from_rx(void) { + if (radio_state != RADIO_RX) { + return; + } + DEBUG("CC1100 going to idle\n"); + cc110x_strobe(CC1100_SIDLE); + radio_state = RADIO_IDLE; +} + +char* cc110x_get_marc_state(void) { + uint8_t state; + + // Save old radio state + uint8_t old_state = radio_state; + + // Read content of status register + state = cc110x_read_status(CC1100_MARCSTATE) & MARC_STATE; + + // Make sure in IDLE state. + // Only goes to IDLE if state was RX/WOR + cc110x_wakeup_from_rx(); + + // Have to put radio back to WOR/RX if old radio state + // was WOR/RX, otherwise no action is necessary + if (old_state == RADIO_WOR || old_state == RADIO_RX) { + cc110x_switch_to_rx(); + } + + switch (state) + { + // Note: it is not possible to read back the SLEEP or XOFF state numbers + // because setting CSn low will make the chip enter the IDLE mode from the + // SLEEP (0) or XOFF (2) states. + case 1: return "IDLE"; + case 3: case 4: case 5: return "MANCAL"; + case 6: case 7: return "FS_WAKEUP"; + case 8: case 12: return "CALIBRATE"; + case 9: case 10: case 11: return "SETTLING"; + case 13: case 14: case 15: return "RX"; + case 16: return "TXRX_SETTLING"; + case 17: return "RXFIFO_OVERFLOW"; + case 18: return "FSTXON"; + case 19: case 20: return "TX"; + case 21: return "RXTX_SETTLING"; + case 22: return "TXFIFO_UNDERFLOW"; + default: return "UNKNOWN"; + } +} + +char* cc110x_state_to_text(uint8_t state) { + switch (state) + { + case RADIO_UNKNOWN: + return "Unknown"; + case RADIO_AIR_FREE_WAITING: + return "CS"; + case RADIO_WOR: + return "WOR"; + case RADIO_IDLE: + return "IDLE"; + case RADIO_SEND_BURST: + return "TX BURST"; + case RADIO_RX: + return "RX"; + case RADIO_SEND_ACK: + return "TX ACK"; + case RADIO_PWD: + return "PWD"; + default: + return "unknown"; + } +} + +void cc110x_print_config(void) { + printf("Current radio state: %s\r\n", cc110x_state_to_text(radio_state)); + printf("Current MARC state: %s\r\n", cc110x_get_marc_state()); + printf("Current channel number: %u\r\n", radio_channel); +} + +void cc110x_switch_to_pwd(void) { + DEBUG("[cc110x_ng] switching to powerdown\n"); + cc110x_wakeup_from_rx(); + cc110x_strobe(CC1100_SPWD); + radio_state = RADIO_PWD; +} + +/*---------------------------------------------------------------------------*/ +int16_t cc110x_set_channel(uint8_t channr) { + uint8_t state = cc110x_read_status(CC1100_MARCSTATE) & MARC_STATE; + if ((state != 1) && (channr > MAX_CHANNR)) { + return -1; + } + write_register(CC1100_CHANNR, channr*10); + radio_channel = channr; + return radio_channel; +} + +#ifdef MODULE_CONFIG +int16_t cc110x_set_config_channel(uint8_t channr) { + int16_t c = cc110x_set_channel(channr); + if (c) { + sysconfig.radio_channel = c; + } + config_save(); + return c; +} +#endif + +int16_t cc110x_get_channel(void) { + return radio_channel; +} + + +/*---------------------------------------------------------------------------*/ +// CC1100 reset functionality +/*---------------------------------------------------------------------------*/ + +static void reset(void) { + cc110x_wakeup_from_rx(); +#ifdef MODULE_CC110x_SPI + cc110x_spi_select(); +#endif + cc110x_strobe(CC1100_SRES); + hwtimer_wait(RTIMER_TICKS(100)); +} + +static void power_up_reset(void) { +#ifdef MODULE_CC110x_SPI + cc110x_spi_unselect(); + cc110x_spi_cs(); + cc110x_spi_unselect(); +#endif + hwtimer_wait(RESET_WAIT_TIME); + reset(); + radio_state = RADIO_IDLE; +} + +static void write_register(uint8_t r, uint8_t value) { + // Save old radio state + uint8_t old_state = radio_state; + + /* Wake up from WOR/RX (if in WOR/RX, else no effect) */ + cc110x_wakeup_from_rx(); + cc110x_write_reg(r, value); + + // Have to put radio back to WOR/RX if old radio state + // was WOR/RX, otherwise no action is necessary + if ((old_state == RADIO_WOR) || (old_state == RADIO_RX)) { + cc110x_switch_to_rx(); + } +} + +static int rd_set_mode(int mode) { + int result; + + // Get current radio mode + if ((radio_state == RADIO_UNKNOWN) || (radio_state == RADIO_PWD)) { + result = RADIO_MODE_OFF; + } + else { + result = RADIO_MODE_ON; + } + + switch (mode) { + case RADIO_MODE_ON: + DEBUG("Enabling rx mode\n"); + cc110x_init_interrupts(); // Enable interrupts + cc110x_setup_rx_mode(); // Set chip to desired mode + break; + case RADIO_MODE_OFF: + cc110x_disable_interrupts(); // Disable interrupts + cc110x_switch_to_pwd(); // Set chip to power down mode + break; + case RADIO_MODE_GET: + // do nothing, just return current mode + default: + // do nothing + break; + } + + // Return previous mode + return result; +} + + diff --git a/drivers/cc110x_ng/cc110x_cc430.c b/drivers/cc110x_ng/cc110x_cc430.c new file mode 100644 index 000000000..66b0d09dd --- /dev/null +++ b/drivers/cc110x_ng/cc110x_cc430.c @@ -0,0 +1,184 @@ +#include +#include +#include +#include +#include +#include + +// ************************************************************************************************* +// @fn Strobe +// @brief Send command to radio. +// @param none +// @return none +// ************************************************************************************************* +uint8_t cc110x_strobe(uint8_t c) { + uint8_t statusByte = 0; + uint16_t int_state, gdo_state; + + // Check for valid strobe command + if((c == 0xBD) || ((c > RF_SRES) && (c < RF_SNOP))) { + int_state = disableIRQ(); + + // Clear the Status read flag + RF1AIFCTL1 &= ~(RFSTATIFG); + + // Wait for radio to be ready for next instruction + while( !(RF1AIFCTL1 & RFINSTRIFG)); + + // Write the strobe instruction + if ((c > RF_SRES) && (c < RF_SNOP)) + { + + gdo_state = cc110x_read_reg(IOCFG2); // buffer IOCFG2 state + cc110x_write_reg(IOCFG2, 0x29); // c-ready to GDO2 + + RF1AINSTRB = c; + if ((RF1AIN & 0x04) == 0x04 ) // chip at sleep mode + { + if ((c == RF_SXOFF) || (c == RF_SPWD) || (c == RF_SWOR) ) { } + else + { + while ((RF1AIN&0x04)== 0x04); // c-ready ? + hwtimer_wait(RTIMER_TICKS(9800)); // Delay for ~810usec at 12MHz CPU clock + } + } + cc110x_write_reg(IOCFG2, gdo_state); // restore IOCFG2 setting + } + else // chip active mode + { + RF1AINSTRB = c; + } + statusByte = RF1ASTATB; + while( !(RF1AIFCTL1 & RFSTATIFG) ); + restoreIRQ(int_state); + } + return statusByte; +} + + +// ************************************************************************************************* +// @fn cc110x_read_reg +// @brief Read byte from register. +// @param none +// @return none +// ************************************************************************************************* +uint8_t cc110x_read_reg(uint8_t addr) { + unsigned char x; + uint16_t int_state; + + int_state = disableIRQ(); + + RF1AINSTR1B = (addr | RF_REGRD); + x = RF1ADOUT1B; + + restoreIRQ(int_state); + return x; +} + + +// ************************************************************************************************* +// @fn cc110x_write_reg +// @brief Write byte to register. +// @param none +// @return none +// ************************************************************************************************* +void cc110x_write_reg(uint8_t addr, uint8_t value) { + volatile unsigned int i; + uint16_t int_state; + + int_state = disableIRQ(); + + while (!(RF1AIFCTL1 & RFINSTRIFG)); // Wait for the Radio to be ready for the next instruction + + RF1AINSTRW = ((addr | RF_REGWR)<<8 ) + value; // Send address + Instruction + while (!(RFDINIFG & RF1AIFCTL1)); + + i = RF1ADOUTB; // Reset RFDOUTIFG flag which contains status byte + + restoreIRQ(int_state); +} + +uint8_t cc110x_read_status(uint8_t addr) { + unsigned char x; + uint16_t int_state; + + int_state = disableIRQ(); + + RF1AINSTR1B = (addr | RF_STATREGRD); + x = RF1ADOUT1B; + + restoreIRQ(int_state); + return x; +} + +// ************************************************************************************************* +// @fn cc110x_readburst_reg +// @brief Read sequence of bytes from register. +// @param none +// @return none +// ************************************************************************************************* +void cc110x_readburst_reg(uint8_t addr, char *buffer, uint8_t count) { + unsigned int i; + uint16_t int_state; + + int_state = disableIRQ(); + + while (!(RF1AIFCTL1 & RFINSTRIFG)); // Wait for the Radio to be ready for next 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 + 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 + + restoreIRQ(int_state); +} + +void cc110x_read_fifo(char *buffer, uint8_t count) { + unsigned int i; + uint16_t int_state; + + int_state = disableIRQ(); + + while (!(RF1AIFCTL1 & RFINSTRIFG)); // Wait for the Radio to be ready for next instruction + RF1AINSTR1B = (RF_RXFIFORD); // Send address + Instruction + + 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[count-1] = RF1ADOUT0B; // Store the last DOUT from Radio Core + + restoreIRQ(int_state); +} +// ************************************************************************************************* +// @fn cc110x_writeburst_reg +// @brief Write sequence of bytes to register. +// @param none +// @return none +// ************************************************************************************************* +uint8_t cc110x_writeburst_reg(uint8_t addr, char *buffer, uint8_t count) { + // Write Burst works wordwise not bytewise - bug known already + unsigned char i; + uint16_t int_state; + + int_state = disableIRQ(); + + while (!(RF1AIFCTL1 & RFINSTRIFG)); // Wait for the Radio to be ready for next instruction + RF1AINSTRW = ((addr | RF_REGWR)<<8 ) + buffer[0]; // Send address + Instruction + + for (i = 1; i < count; i++) + { + RF1ADINB = buffer[i]; // Send data + while (!(RFDINIFG & RF1AIFCTL1)); // Wait for TX to finish + } + i = RF1ADOUTB; // Reset RFDOUTIFG flag which contains status byte + + restoreIRQ(int_state); + return count; +} diff --git a/drivers/cc110x_ng/cc110x_spi.c b/drivers/cc110x_ng/cc110x_spi.c new file mode 100644 index 000000000..cd5730386 --- /dev/null +++ b/drivers/cc110x_ng/cc110x_spi.c @@ -0,0 +1,133 @@ +/****************************************************************************** +Copyright 2010, Freie Universitaet Berlin (FUB). All rights reserved. + +These sources were developed at the Freie Universitaet Berlin, Computer Systems +and Telematics group (http://cst.mi.fu-berlin.de). +------------------------------------------------------------------------------- +This file is part of µkleos. + +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +FeuerWare is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see http://www.gnu.org/licenses/ . +-------------------------------------------------------------------------------- +For further information and questions please use the web site + http://scatterweb.mi.fu-berlin.de +and the mailinglist (subscription via web site) + scatterweb@lists.spline.inf.fu-berlin.de +*******************************************************************************/ + +/** + * @ingroup dev_cc110x + * @{ + */ + +/** + * @file + * @internal + * @brief TI Chipcon CC1100 SPI driver + * + * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project + * @author Thomas Hillebrandt + * @author Heiko Will + * @version $Revision: 1775 $ + * + * @note $Id: cc110x_spi.c 1775 2010-01-26 09:37:03Z hillebra $ + */ + +#include + +#include +#include +#include +#include +#include + +#include + +/*---------------------------------------------------------------------------*/ +// CC1100 SPI access +/*---------------------------------------------------------------------------*/ + +#define NOBYTE 0xFF + +uint8_t cc110x_writeburst_reg(uint8_t addr, char *src, uint8_t count) { + int i = 0; + unsigned int cpsr = disableIRQ(); + cc110x_spi_select(); + cc110x_txrx(addr | CC1100_WRITE_BURST); + while (i < count) { + cc110x_txrx(src[i]); + i++; + } + cc110x_spi_unselect(); + restoreIRQ(cpsr); + return count; +} + +void cc110x_readburst_reg(uint8_t addr, char *buffer, uint8_t count) { + int i = 0; + unsigned int cpsr = disableIRQ(); + cc110x_spi_select(); + cc110x_txrx(addr | CC1100_READ_BURST); + while (i < count) { + buffer[i] = cc110x_txrx(NOBYTE); + i++; + } + cc110x_spi_unselect(); + restoreIRQ(cpsr); +} + +void cc110x_read_fifo(char *buffer, uint8_t count) { + cc110x_readburst_reg(CC1100_RXFIFO, buffer,count); +} + +void cc110x_write_reg(uint8_t addr, uint8_t value) { + unsigned int cpsr = disableIRQ(); + cc110x_spi_select(); + cc110x_txrx(addr); + cc110x_txrx(value); + cc110x_spi_unselect(); + restoreIRQ(cpsr); +} + +uint8_t cc110x_read_reg(uint8_t addr) { + uint8_t result; + unsigned int cpsr = disableIRQ(); + cc110x_spi_select(); + cc110x_txrx(addr | CC1100_READ_SINGLE); + result = cc110x_txrx(NOBYTE); + cc110x_spi_unselect(); + restoreIRQ(cpsr); + return result; +} + +uint8_t cc110x_read_status(uint8_t addr) { + uint8_t result; + unsigned int cpsr = disableIRQ(); + cc110x_spi_select(); + cc110x_txrx(addr | CC1100_READ_BURST); + result = cc110x_txrx(NOBYTE); + cc110x_spi_unselect(); + restoreIRQ(cpsr); + return result; +} + +uint8_t cc110x_strobe(uint8_t c) { + uint8_t result; + unsigned int cpsr = disableIRQ(); + cc110x_spi_select(); + result = cc110x_txrx(c); + cc110x_spi_unselect(); + restoreIRQ(cpsr); + return result; +} + +/** @} */ diff --git a/drivers/cc110x_ng/include/cc110x-arch.h b/drivers/cc110x_ng/include/cc110x-arch.h new file mode 100644 index 000000000..3a990b1ba --- /dev/null +++ b/drivers/cc110x_ng/include/cc110x-arch.h @@ -0,0 +1,50 @@ +/****************************************************************************** +Copyright 2008, Freie Universitaet Berlin (FUB). All rights reserved. + +These sources were developed at the Freie Universitaet Berlin, Computer Systems +and Telematics group (http://cst.mi.fu-berlin.de). +------------------------------------------------------------------------------- +This file is part of FeuerWare. + +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +FeuerWare is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see http://www.gnu.org/licenses/ . +-------------------------------------------------------------------------------- +For further information and questions please use the web site + http://scatterweb.mi.fu-berlin.de +and the mailinglist (subscription via web site) + scatterweb@lists.spline.inf.fu-berlin.de +*******************************************************************************/ + +/** + * @file + * @ingroup LPC2387 + * @brief CC1100 LPC2387 dependend functions + * + * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project + * @author Heiko Will + * @version $Revision: 1775 $ + * + * @note $Id: arch_cc110x.h 1775 2010-01-26 09:37:03Z hillebra $ + */ + +#include + +uint8_t cc110x_txrx(uint8_t c); + +void cc110x_gdo0_enable(void); +void cc110x_gdo0_disable(void); +void cc110x_gdo2_enable(void); +void cc110x_gdo2_disable(void); +void cc110x_init_interrupts(void); + +void cc110x_before_send(void); +void cc110x_after_send(void); diff --git a/drivers/cc110x_ng/include/cc110x-config.h b/drivers/cc110x_ng/include/cc110x-config.h new file mode 100644 index 000000000..3531d71df --- /dev/null +++ b/drivers/cc110x_ng/include/cc110x-config.h @@ -0,0 +1,96 @@ +#ifndef CC1100_CONFIG_H +#define CC1100_CONFIG_H + +#include +#include + +/** CC1100 register configuration */ +typedef struct { + uint8_t _IOCFG2; + uint8_t _IOCFG1; + uint8_t _IOCFG0; + uint8_t _FIFOTHR; + uint8_t _SYNC1; + uint8_t _SYNC0; + uint8_t _PKTLEN; + uint8_t _PKTCTRL1; + uint8_t _PKTCTRL0; + uint8_t _ADDR; + uint8_t _CHANNR; + uint8_t _FSCTRL1; + uint8_t _FSCTRL0; + uint8_t _FREQ2; + uint8_t _FREQ1; + uint8_t _FREQ0; + uint8_t _MDMCFG4; + uint8_t _MDMCFG3; + uint8_t _MDMCFG2; + uint8_t _MDMCFG1; + uint8_t _MDMCFG0; + uint8_t _DEVIATN; + uint8_t _MCSM2; + uint8_t _MCSM1; + uint8_t _MCSM0; + uint8_t _FOCCFG; + uint8_t _BSCFG; + uint8_t _AGCCTRL2; + uint8_t _AGCCTRL1; + uint8_t _AGCCTRL0; + uint8_t _WOREVT1; + uint8_t _WOREVT0; + uint8_t _WORCTRL; + uint8_t _FREND1; + uint8_t _FREND0; + uint8_t _FSCAL3; + uint8_t _FSCAL2; + uint8_t _FSCAL1; + uint8_t _FSCAL0; +} cc110x_reg_t; + +/** CC1100 radio configuration */ +typedef struct { + cc110x_reg_t reg_cfg; ///< CC1100 register configuration + uint8_t pa_power; ///< Output power setting +} cc110x_cfg_t; + +/** + * @brief Radio Control Flags + */ +typedef struct +{ + uint32_t TOF; ///< Time of flight of the last packet and last ACK + timex_t TOA; ///< Time of packet arriveal + uint32_t TCP; ///< Time to compute packet + unsigned RPS : 16; ///< Raw packets sent to transmit last packet + unsigned RTC : 8; ///< Retransmission count of last send packet + unsigned _RSSI : 8; ///< The RSSI value of last received packet + unsigned RSSI_SEND : 8; ///< The RSSI value of the last send unicast packet of this node + unsigned _LQI : 8; ///< The LQI value of the last received packet + unsigned LL_ACK : 1; ///< Is set if Link-Level ACK is received, otherwise 0 (reset on new burst) + unsigned CAA : 1; ///< The status of the air (1 = air free, 0 = air not free) + unsigned CRC : 1; ///< The CRC status of last received packet (1 = OK, 0 = not OK) + unsigned SEQ : 1; ///< Sequence number (toggles between 0 and 1) + unsigned MAN_WOR : 1; ///< Manual WOR set (for randomized WOR times => no synch) + unsigned KT_RES_ERR : 1; ///< A hwtimer resource error has occurred (no free timers available) + unsigned TX : 1; ///< State machine TX lock, only ACKs will be received + unsigned WOR_RST : 1; ///< Reset CC1100 real time clock (WOR) on next WOR strobe +} cc110x_flags; + +/** + * @brief Statistic interface for debugging + */ +typedef struct cc110x_statistic { + uint32_t packets_in; + uint32_t packets_in_crc_fail; + uint32_t packets_in_while_tx; + uint32_t packets_in_dups; + uint32_t packets_in_up; + uint32_t packets_out; + uint32_t packets_out_broadcast; + uint32_t raw_packets_out; + uint32_t acks_send; + uint32_t rx_buffer_max; + uint32_t watch_dog_resets; +} cc110x_statistic_t; + +#endif diff --git a/drivers/cc110x_ng/include/cc110x-defaultSettings.h b/drivers/cc110x_ng/include/cc110x-defaultSettings.h new file mode 100644 index 000000000..d15a45cd5 --- /dev/null +++ b/drivers/cc110x_ng/include/cc110x-defaultSettings.h @@ -0,0 +1,110 @@ +/****************************************************************************** +Copyright 2008, Freie Universitaet Berlin (FUB). All rights reserved. + +These sources were developed at the Freie Universitaet Berlin, Computer Systems +and Telematics group (http://cst.mi.fu-berlin.de). +------------------------------------------------------------------------------- +This file is part of FeuerWare. + +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +FeuerWare is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see http://www.gnu.org/licenses/ . +-------------------------------------------------------------------------------- +For further information and questions please use the web site + http://scatterweb.mi.fu-berlin.de +and the mailinglist (subscription via web site) + scatterweb@lists.spline.inf.fu-berlin.de +*******************************************************************************/ + +#ifndef CC1100_DEFAULTSETTINGS_H +#define CC1100_DEFAULTSETTINGS_H + +/** + * @ingroup dev_cc110x + * @{ + */ + +/** + * @file + * @brief TI Chipcon CC110x default settings + * + * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project + * @author Thomas Hillebrandt + * @author Heiko Will + * @version $Revision: 2139 $ + * + * @note $Id: cc110x-defaultSettings.h 2139 2010-05-26 08:04:04Z hillebra $ + */ + +#include + +// returns hwtimer ticks per us +#define RTIMER_TICKS(us) HWTIMER_TICKS(us) + +#define TIMER_TICK_USEC_RES (122) + +// Default PA table index (output power) +#define PATABLE (11) + +// Watchdog cycle time in seconds, set 0 to disable watchdog +#define CC1100_WATCHDOG_PERIOD (5) + +// Number of transmission retries for unicast packets (constant RX mode) +#define TRANSMISSION_RETRIES_CRX_UC (5) + +// Number of transmission retries for unicast packets (WOR mode) +#define TRANSMISSION_RETRIES_WOR_UC (1) + +// Number of transmission retries for broadcast packets (constant RX mode) +#define TRANSMISSION_RETRIES_CRX_BC (0) + +// Number of transmission retries for broadcast packets (WOR mode) +#define TRANSMISSION_RETRIES_WOR_BC (0) + +// Time before chip goes back to RX (= stays in PWD after incoming packet) +#define WOR_TIMEOUT_1 (3200) // ~ 32 milliseconds + +// Time before chip goes back to WOR (= stays in RX after elapsed WOR_TIMEOUT_1) +#define WOR_TIMEOUT_2 (800) // ~ 8 milliseconds + +// XOSC startup + FS calibration (300 + 809 us ~ 1.38 ms) +#define FS_CAL_TIME RTIMER_TICKS(12 * TIMER_TICK_USEC_RES) + +// Manual FS calibration (721 us) +#define MANUAL_FS_CAL_TIME RTIMER_TICKS(7 * TIMER_TICK_USEC_RES) + +// Reset wait time (in reset procedure) +#define RESET_WAIT_TIME RTIMER_TICKS(4 * TIMER_TICK_USEC_RES) + +// Time chip needs to go to RX +#define IDLE_TO_RX_TIME RTIMER_TICKS(1 * TIMER_TICK_USEC_RES) + +// Time chip needs to go to RX and CS signal is ready +#define CS_READY_TIME RTIMER_TICKS(3 * TIMER_TICK_USEC_RES) + +// Default RX interval for WOR in milliseconds +#define T_RX_INTERVAL (542) + +// Time of packet interval in microseconds (at 400 kbps) +#define T_PACKET_INTERVAL (3800) + +// The size of the configuration array for CC1100 in bytes +#define CC1100_CONF_SIZE (39) + +// The default channel number (0-24) for CC1100 +#define CC1100_DEFAULT_CHANNR (0) + +// Burst retry to TX switch time (measured ~ 230 us) +#define BURST_RETRY_TX_SWITCH_TIME (23) + + +/** @} */ +#endif diff --git a/drivers/cc110x_ng/include/cc110x-internal.h b/drivers/cc110x_ng/include/cc110x-internal.h new file mode 100644 index 000000000..409c3b988 --- /dev/null +++ b/drivers/cc110x_ng/include/cc110x-internal.h @@ -0,0 +1,218 @@ +/****************************************************************************** +Copyright 2008, Freie Universitaet Berlin (FUB). All rights reserved. + +These sources were developed at the Freie Universitaet Berlin, Computer Systems +and Telematics group (http://cst.mi.fu-berlin.de). +------------------------------------------------------------------------------- +This file is part of FeuerWare. + +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +FeuerWare is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see http://www.gnu.org/licenses/ . +-------------------------------------------------------------------------------- +For further information and questions please use the web site + http://scatterweb.mi.fu-berlin.de +and the mailinglist (subscription via web site) + scatterweb@lists.spline.inf.fu-berlin.de +*******************************************************************************/ + +#ifndef CC1100_INTERNAL_H +#define CC1100_INTERNAL_H + +/** + * @ingroup dev_cc110x + * @{ + */ + +/** + * @file + * @internal + * @brief TI Chipcon CC110x internal hardware constants + * + * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project + * @author Thomas Hillebrandt + * @author Heiko Will + * @version $Revision: 1231 $ + * + * @note $Id: cc110x-internal.h 1231 2009-08-20 08:31:32Z baar $ + */ + +#define FIXED_PKTLEN (0x00) ///< Fixed length packets, length configured in PKTLEN register. +#define VARIABLE_PKTLEN (0x01) ///< Variable length packets, packet length configured by the first + ///< byte after synch word. + +/** + * @name Bitmasks for reading out status register values + * @{ + */ + +/** + * @brief Bitmask (=10000000) for reading CRC_OK. + * + * If CRC_OK == 1: CRC for received data OK (or CRC disabled). + * If CRC_OK == 0: CRC error in received data. + */ +#define CRC_OK (0x80) +/** + * @brief Bitmask (=01111111) for reading LQI_EST. + * + * The Link Quality Indicator estimates how easily a received signal can be demodulated. + */ +#define LQI_EST (0x7F) +#define I_RSSI (0x00) ///< Index 0 contains RSSI information (from optionally appended packet status bytes). +#define I_LQI (0x01) ///< Index 1 contains LQI & CRC_OK information (from optionally appended packet status bytes). +#define MARC_STATE (0x1F) ///< Bitmask (=00011111) for reading MARC_STATE in MARCSTATE status register. +#define CS (0x40) ///< Bitmask (=01000000) for reading CS (Carrier Sense) in PKTSTATUS status register. +#define PQT_REACHED (0x20) ///< Bitmask (=00100000) for reading PQT_REACHED (Preamble Quality reached) in PKTSTATUS status register. +#define CCA (0x10) ///< Bitmask (=00010000) for reading CCA (clear channel assessment) in PKTSTATUS status register. +#define SFD (0x08) ///< Bitmask (=00001000) for reading SFD (Sync word found) in PKTSTATUS status register. +#define GDO2 (0x04) ///< Bitmask (=00000100) for reading GDO2 (current value on GDO2 pin) in PKTSTATUS status register. +#define GDO1 (0x02) ///< Bitmask (=00000010) for reading GDO1 (current value on GDO1 pin) in PKTSTATUS status register. +#define GDO0 (0x01) ///< Bitmask (=00000001) for reading GDO0 (current value on GDO0 pin) in PKTSTATUS status register. +#define TXFIFO_UNDERFLOW (0x80) ///< Bitmask (=10000000) for reading TXFIFO_UNDERFLOW in TXBYTES status register. +#define BYTES_IN_TXFIFO (0x7F) ///< Bitmask (=01111111) for reading NUM_TXBYTES in TXBYTES status register. +#define RXFIFO_OVERFLOW (0xBF) ///< Bitmask (=10000000) for reading RXFIFO_OVERFLOW in RXBYTES status register. +#define BYTES_IN_RXFIFO (0xFF) ///< Bitmask (=01111111) for reading NUM_RXBYTES in RXBYTES status register. +/** @} */ + +/** + * @name Bitmasks for reading out configuration register values + * @{ + */ +#define PKT_LENGTH_CONFIG (0x03) ///< Bitmask (=00000011) for reading LENGTH_CONFIG in PKTCTRL0 configuration register. +/** @} */ + +/** + * @name Definitions to support burst/single access + * @{ + */ +#define CC1100_WRITE_BURST (0x40) ///< Offset for burst write. +#define CC1100_READ_SINGLE (0x80) ///< Offset for read single byte. +#define CC1100_READ_BURST (0xC0) ///< Offset for read burst. +#define CC1100_NOBYTE (0x00) ///< No command (for reading). +/** @} */ + +/** + * @name Configuration Registers (47x) + * @{ + */ +#define CC1100_IOCFG2 (0x00) ///< GDO2 output pin configuration +#define CC1100_IOCFG1 (0x01) ///< GDO1 output pin configuration +#define CC1100_IOCFG0 (0x02) ///< GDO0 output pin configuration +#define CC1100_FIFOTHR (0x03) ///< RX FIFO and TX FIFO thresholds +#define CC1100_SYNC1 (0x04) ///< Sync word, high byte +#define CC1100_SYNC0 (0x05) ///< Sync word, low byte +#define CC1100_PKTLEN (0x06) ///< Packet length +#define CC1100_PKTCTRL1 (0x07) ///< Packet automation control +#define CC1100_PKTCTRL0 (0x08) ///< Packet automation control +#define CC1100_ADDR (0x09) ///< Device address +#define CC1100_CHANNR (0x0A) ///< Channel number +#define CC1100_FSCTRL1 (0x0B) ///< Frequency synthesizer control +#define CC1100_FSCTRL0 (0x0C) ///< Frequency synthesizer control +#define CC1100_FREQ2 (0x0D) ///< Frequency control word, high byte +#define CC1100_FREQ1 (0x0E) ///< Frequency control word, middle byte +#define CC1100_FREQ0 (0x0F) ///< Frequency control word, low byte +#define CC1100_MDMCFG4 (0x10) ///< Modem configuration +#define CC1100_MDMCFG3 (0x11) ///< Modem configuration +#define CC1100_MDMCFG2 (0x12) ///< Modem configuration +#define CC1100_MDMCFG1 (0x13) ///< Modem configuration +#define CC1100_MDMCFG0 (0x14) ///< Modem configuration +#define CC1100_DEVIATN (0x15) ///< Modem deviation setting +#define CC1100_MCSM2 (0x16) ///< Main Radio Control State Machine configuration +#define CC1100_MCSM1 (0x17) ///< Main Radio Control State Machine configuration +#define CC1100_MCSM0 (0x18) ///< Main Radio Control State Machine configuration +#define CC1100_FOCCFG (0x19) ///< Frequency Offset Compensation configuration +#define CC1100_BSCFG (0x1A) ///< Bit Synchronization configuration +#define CC1100_AGCCTRL2 (0x1B) ///< AGC control +#define CC1100_AGCCTRL1 (0x1C) ///< AGC control +#define CC1100_AGCCTRL0 (0x1D) ///< AGC control +#define CC1100_WOREVT1 (0x1E) ///< High byte Event 0 timeout +#define CC1100_WOREVT0 (0x1F) ///< Low byte Event 0 timeout +#define CC1100_WORCTRL (0x20) ///< Wake On Radio control +#define CC1100_FREND1 (0x21) ///< Front end RX configuration +#define CC1100_FREND0 (0x22) ///< Front end TX configuration +#define CC1100_FSCAL3 (0x23) ///< Frequency synthesizer calibration +#define CC1100_FSCAL2 (0x24) ///< Frequency synthesizer calibration +#define CC1100_FSCAL1 (0x25) ///< Frequency synthesizer calibration +#define CC1100_FSCAL0 (0x26) ///< Frequency synthesizer calibration +#define CC1100_RCCTRL1 (0x27) ///< RC oscillator configuration +#define CC1100_RCCTRL0 (0x28) ///< RC oscillator configuration +#define CC1100_FSTEST (0x29) ///< Frequency synthesizer calibration control +#define CC1100_PTEST (0x2A) ///< Production test +#define CC1100_AGCTEST (0x2B) ///< AGC test +#define CC1100_TEST2 (0x2C) ///< Various test settings +#define CC1100_TEST1 (0x2D) ///< Various test settings +#define CC1100_TEST0 (0x2E) ///< Various test settings +/** @} */ + +/** + * @name Strobe commands (14x) + * @{ + */ +#define CC1100_SRES (0x30) ///< Reset chip. +/** + * @brief Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1). + * + * If in RX/TX: Go to a wait state where only the synthesizer is running (for quick RX / TX turnaround). + */ +#define CC1100_SFSTXON (0x31) +#define CC1100_SXOFF (0x32) ///< Turn off crystal oscillator. +#define CC1100_SCAL (0x33) ///< Calibrate frequency synthesizer and turn it off (enables quick start). +#define CC1100_SRX (0x34) ///< Enable RX. Perform calibration first if coming from IDLE and MCSM0.FS_AUTOCAL=1. +/** + * In IDLE state: Enable TX. Perform calibration first if MCSM0.FS_AUTOCAL=1. + * If in RX state and CCA is enabled: Only go to TX if channel is clear. + */ +#define CC1100_STX (0x35) +#define CC1100_SIDLE (0x36) ///< Exit RX / TX, turn off frequency synthesizer and exit WOR mode if applicable. +#define CC1100_SAFC (0x37) ///< Perform AFC adjustment of the frequency synthesizer +#define CC1100_SWOR (0x38) ///< Start automatic RX polling sequence (Wake-on-Radio) +#define CC1100_SPWD (0x39) ///< Enter power down mode when CSn goes high. +#define CC1100_SFRX (0x3A) ///< Flush the RX FIFO buffer (CC1100 should be in IDLE state). +#define CC1100_SFTX (0x3B) ///< Flush the TX FIFO buffer (CC1100 should be in IDLE state). +#define CC1100_SWORRST (0x3C) ///< Reset real time clock. +#define CC1100_SNOP (0x3D) ///< No operation. May be used to pad strobe commands to two bytes for simpler software. +/** @} */ + +/** + * @name Status registers (12x) + * @{ + */ +#define CC1100_PARTNUM (0x30) ///< Part number of CC1100. +#define CC1100_VERSION (0x31) ///< Current version number. +#define CC1100_FREQEST (0x32) ///< Frequency Offset Estimate. +#define CC1100_LQI (0x33) ///< Demodulator estimate for Link Quality. +#define CC1100_RSSI (0x34) ///< Received signal strength indication. +#define CC1100_MARCSTATE (0x35) ///< Control state machine state. +#define CC1100_WORTIME1 (0x36) ///< High byte of WOR timer. +#define CC1100_WORTIME0 (0x37) ///< Low byte of WOR timer. +#define CC1100_PKTSTATUS (0x38) ///< Current GDOx status and packet status. +#define CC1100_VCO_VC_DAC (0x39) ///< Current setting from PLL calibration module. +#define CC1100_TXBYTES (0x3A) ///< Underflow and number of bytes in the TX FIFO. +#define CC1100_RXBYTES (0x3B) ///< Overflow and number of bytes in the RX FIFO. +/** @} */ + +/** + * @name Multi byte registers + * @{ + */ +/** + * @brief Register for eight user selected output power settings. + * + * 3-bit FREND0.PA_POWER value selects the PATABLE entry to use. + */ +#define CC1100_PATABLE (0x3E) +#define CC1100_TXFIFO (0x3F) ///< TX FIFO: Write operations write to the TX FIFO (SB: +0x00; BURST: +0x40) +#define CC1100_RXFIFO (0x3F) ///< RX FIFO: Read operations read from the RX FIFO (SB: +0x80; BURST: +0xC0) + +/** @} */ + +#endif diff --git a/drivers/cc110x_ng/include/cc110x-reg.h b/drivers/cc110x_ng/include/cc110x-reg.h new file mode 100644 index 000000000..02756ca5f --- /dev/null +++ b/drivers/cc110x_ng/include/cc110x-reg.h @@ -0,0 +1,83 @@ +/** + * @file cc110x-reg.h + * @ingroup dev_cc110x_ng + * @brief Access to CC110X registers + * + * @author Freie Uniersität Berlin, Computer Systems & Telematics, µkleos + * @author Oliver Hahm + +/** + * @brief Write a set of bytes using burst mode (if available) + * + * @param addr Destination register + * @param buffer Data to be written + * @param count Size of data + * + * @return Written bytes + */ +uint8_t cc110x_writeburst_reg(uint8_t addr, char *buffer, uint8_t count); + +/** + * @brief Read a set of bytes using burst mode (if available) + * + * @param addr Source register + * @param buffer Buffer to store read data + * @param count Size of data to be read + */ +void cc110x_readburst_reg(uint8_t addr, char *buffer, uint8_t count); + +/** + * @brief Read bytes from RXFIFO + * + * @param buffer Buffer to store read data + * @param count Size of data to be read + * + * @note: Calls cc110x_readburst_reg if not dedicated fifo read command + * available + */ +void cc110x_read_fifo(char *buffer, uint8_t count); + +/** + * @brief Write one byte to a register + * + * @param addr Destinatoin register + * @param value New value + */ +void cc110x_write_reg(uint8_t addr, uint8_t value); + +/** + * @brief Read a byte from register + * + * @param addr Source register + * + * @return Read state and value of register + */ +uint8_t cc110x_read_reg(uint8_t addr); + +/** + * @brief Read state of a register + * + * @param addr Source register + * + * @return State of register + */ +uint8_t cc110x_read_status(uint8_t addr); + +/** + * @brief Sends a command strobe + * + * @param c Command code + * + * @return Command response + */ +uint8_t cc110x_strobe(uint8_t c); + +#endif diff --git a/drivers/cc110x_ng/include/cc110x_ng.h b/drivers/cc110x_ng/include/cc110x_ng.h new file mode 100644 index 000000000..5d0238951 --- /dev/null +++ b/drivers/cc110x_ng/include/cc110x_ng.h @@ -0,0 +1,135 @@ +#ifndef CC1100_H +#define CC1100_H + +#include +#include +#include +#include + +#define CC1100_MAX_DATA_LENGTH (58) + +#define CC1100_HEADER_LENGTH (3) ///< Header covers SRC, DST and FLAGS + +#define CC1100_BROADCAST_ADDRESS (0x00) ///< CC1100 broadcast address + +#define MAX_UID (0xFF) ///< Maximum UID of a node is 255 +#define MIN_UID (0x01) ///< Minimum UID of a node is 1 + +#define MIN_CHANNR (0) ///< Minimum channel number +#define MAX_CHANNR (24) ///< Maximum channel number + +#define MIN_OUTPUT_POWER (0) ///< Minimum output power value +#define MAX_OUTPUT_POWER (11) ///< Maximum output power value + +#define PACKET_LENGTH (0x3E) ///< Packet length = 62 Bytes. +#define CC1100_SYNC_WORD_TX_TIME (90000) // loop count (max. timeout ~ 15 ms) to wait for + // sync word to be transmitted (GDO2 from low to high) +/** + * @name Defines used as state values for state machine + * @{ + */ +#define RADIO_UNKNOWN (0) +#define RADIO_AIR_FREE_WAITING (1) +#define RADIO_WOR (2) +#define RADIO_IDLE (3) +#define RADIO_SEND_BURST (4) +#define RADIO_RX (5) +#define RADIO_SEND_ACK (6) +#define RADIO_PWD (7) + +/** @} */ + +extern volatile cc110x_flags rflags; ///< Radio flags +extern char cc110x_conf[]; + +/** + * @brief CC1100 layer 0 protocol + * + *
+---------------------------------------------------
+|        |         |         |       |            |
+| Length | Address | PhySrc  | Flags |    Data    |
+|        |         |         |       |            |
+---------------------------------------------------
+  1 byte   1 byte    1 byte   1 byte   <= 58 bytes
+
+Flags:
+		Bit | Meaning
+		--------------------
+		7:4	| -
+		3:1 | Protocol
+		  0 | Identification
+
+Notes: +\li length & address are given by CC1100 +\li Identification is increased is used to scan duplicates. It must be increased + for each new packet and kept for packet retransmissions. + */ +typedef struct __attribute__ ((packed)) { + uint8_t length; ///< Length of the packet (without length byte) + uint8_t address; ///< Destination address + uint8_t phy_src; ///< Source address (physical source) + uint8_t flags; ///< Flags + uint8_t data[CC1100_MAX_DATA_LENGTH]; ///< Data (high layer protocol) +} cc110x_packet_t; + +typedef struct { + uint8_t rssi; + uint8_t lqi; + cc110x_packet_t packet; +} rx_buffer_t; + +enum radio_mode { + RADIO_MODE_GET = -1, ///< leave mode unchanged + RADIO_MODE_OFF = 0, ///< turn radio off + RADIO_MODE_ON = 1 ///< turn radio on +}; + +extern rx_buffer_t cc110x_rx_buffer[]; + +extern volatile uint8_t rx_buffer_next; ///< Next packet in RX queue + +extern volatile uint8_t radio_state; ///< Radio state +extern cc110x_statistic_t cc110x_statistic; + +int transceiver_pid; ///< the transceiver thread pid + +void cc110x_init(int transceiver_pid); + +void cc110x_rx_handler(void); + +uint8_t cc110x_send(cc110x_packet_t *pkt); + +uint8_t cc110x_get_buffer_pos(void); + +void cc110x_setup_rx_mode(void); +void cc110x_switch_to_rx(void); +void cc110x_wakeup_from_rx(void); +void cc110x_switch_to_pwd(void); + +void cc110x_disable_interrupts(void); +int16_t cc110x_set_config_channel(uint8_t channr); +int16_t cc110x_set_channel(uint8_t channr); +int16_t cc110x_get_channel(void); + +radio_address_t cc110x_set_address(radio_address_t addr); +radio_address_t cc110x_set_config_address(radio_address_t addr); +radio_address_t cc110x_get_address(void); +void cc110x_set_monitor(uint8_t mode); + +void cc110x_print_config(void); + +/** + * @brief GDO0 interrupt handler. + */ +void cc110x_gdo0_irq(void); + +/** + * @brief GDO2 interrupt handler. + * + * @note Wakes up MCU on packet reception. + */ +void cc110x_gdo2_irq(void); + + +#endif diff --git a/board/msba2/include/board-conf.h b/drivers/cc110x_ng/include/cc110x_spi.h similarity index 70% rename from board/msba2/include/board-conf.h rename to drivers/cc110x_ng/include/cc110x_spi.h index 2c8824f1f..274f54412 100644 --- a/board/msba2/include/board-conf.h +++ b/drivers/cc110x_ng/include/cc110x_spi.h @@ -23,46 +23,35 @@ For further information and questions please use the web site and the mailinglist (subscription via web site) scatterweb@lists.spline.inf.fu-berlin.de *******************************************************************************/ - -#ifndef BOARDCONF_H_ -#define BOARDCONF_H_ - /** - * @ingroup conf - * @ingroup msba2 - * + * @ingroup dev_cc110x * @{ */ /** * @file - * @brief MSB-A2 board configuration + * @internal + * @brief TI Chipcon CC1100 SPI driver * * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project - * @author baar - * @version $Revision$ + * @author Thomas Hillebrandt + * @author Heiko Will + * @version $Revision: 1775 $ * - * @note $Id$ + * @note $Id: cc110x_spi.h 1775 2010-01-26 09:37:03Z hillebra $ */ -#define FEUERWARE_CONF_BOARD_NAME "FU Berlin MSB-A2" - -#ifdef MODULE_CC110X -#define FEUERWARE_CONF_NUM_RADIOS 1 -#else -#define FEUERWARE_CONF_NUM_RADIOS 0 -#endif - -// if FAT is enabled this board supports files -#define FEUERWARE_CONF_CORE_SUPPORTS_FILES defined(MODULE_FAT) +#ifndef CC1100_SPI_H_ +#define CC1100_SPI_H_ -#ifdef MODULE_FAT -#define CFG_CONF_MEM_SIZE 0x7FFFFFFF -#define SYSLOG_CONF_NUM_INTERFACES 2 -#else -#define SYSLOG_CONF_NUM_INTERFACES 1 -#endif +int cc110x_get_gdo0(void); +int cc110x_get_gdo1(void); +int cc110x_get_gdo2(void); +void cc110x_spi_init(void); +void cc110x_spi_cs(void); +void cc110x_spi_select(void); +void cc110x_spi_unselect(void); /** @} */ -#endif /* BOARDCONF_H_ */ +#endif /* CC1100_SPI_H_ */ diff --git a/drivers/include/diskio.h b/drivers/include/diskio.h new file mode 100644 index 000000000..2dc672dfe --- /dev/null +++ b/drivers/include/diskio.h @@ -0,0 +1,107 @@ +/*----------------------------------------------------------------------- +/ Low level disk interface modlue include file (C)ChaN, 2010 +/-----------------------------------------------------------------------*/ + +#ifndef DEF_DISKIO +#define DEF_DISKIO + +#include + +#define DN_MCI 0 /* Physical drive number for MCI */ +#define DN_NAND 1 /* Physical drive number for NAND flash */ + +/** + * @def MCI_PWRSAVE + * @ingroup conf + * @brief Powerdown mode to use between mci operations + */ +#ifndef MCI_PWRSAVE +#define MCI_PWRSAVE 0 +#endif + +/* These functions are defined in asmfunc.S */ +void Copy_al2un (unsigned char *dst, const unsigned long *src, int count); /* Copy aligned to unaligned. */ +void Copy_un2al (unsigned long *dst, const unsigned char *src, int count); /* Copy unaligned to aligned. */ + + +/* Status of Disk Functions */ +typedef unsigned char DSTATUS; + +/* Results of Disk Functions */ +typedef enum { + RES_OK = 0, /* 0: Successful */ + RES_ERROR, /* 1: R/W Error */ + RES_WRPRT, /* 2: Write Protected */ + RES_NOTRDY, /* 3: Not Ready */ + RES_PARERR /* 4: Invalid Parameter */ +} DRESULT; + + +/*---------------------------------------*/ +/* Prototypes for disk control functions */ + +DSTATUS disk_initialize (unsigned char); +DSTATUS disk_status (unsigned char); +DRESULT disk_read (unsigned char, unsigned char*, unsigned long, unsigned char); +DRESULT disk_write (unsigned char, const unsigned char*, unsigned long, unsigned char); +DRESULT disk_ioctl (unsigned char, unsigned char, void*); + + + +/* Disk Status Bits (DSTATUS) */ + +#define STA_NOINIT 0x01 /* Drive not initialized */ +#define STA_NODISK 0x02 /* No medium in the drive */ +#define STA_PROTECT 0x04 /* Write protected */ + + +/* Command code for disk_ioctrl fucntion */ + +/* Generic ioctl command (defined for FatFs) */ +#define CTRL_SYNC 0 /* Flush disk cache (for write functions) */ +#define GET_SECTOR_COUNT 1 /* Get media size (for only f_mkfs()) */ +#define GET_SECTOR_SIZE 2 /* Get sector size (for multiple sector size (_MAX_SS >= 1024)) */ +#define GET_BLOCK_SIZE 3 /* Get erase block size (for only f_mkfs()) */ +#define CTRL_ERASE_SECTOR 4 /* Force erased a block of sectors (for only _USE_ERASE) */ + +/* Generic ioctl command */ +#define CTRL_POWER 5 /* Get/Set power status */ +#define CTRL_LOCK 6 /* Lock/Unlock media removal */ +#define CTRL_EJECT 7 /* Eject media */ + +/* MMC/SDC specific ioctl command */ +#define MMC_GET_TYPE 10 /* Get card type */ +#define MMC_GET_CSD 11 /* Get CSD */ +#define MMC_GET_CID 12 /* Get CID */ +#define MMC_GET_OCR 13 /* Get OCR */ +#define MMC_GET_SDSTAT 14 /* Get SD status */ + +/* ATA/CF specific ioctl command */ +#define ATA_GET_REV 20 /* Get F/W revision */ +#define ATA_GET_MODEL 21 /* Get model name */ +#define ATA_GET_SN 22 /* Get serial number */ + +/* NAND specific ioctl command */ +#define NAND_FORMAT 30 /* Create physical format */ + + + +/*---------------------------------------------*/ +/* Prototypes for each physical disk functions */ + + +DSTATUS NAND_initialize (void); +DSTATUS NAND_status (void); +DRESULT NAND_read (unsigned char*, unsigned long, unsigned char); +DRESULT NAND_write (const unsigned char*, unsigned long, unsigned char); +DRESULT NAND_ioctl (unsigned char, void*); + +DSTATUS MCI_initialize (void); +DSTATUS MCI_status (void); +DRESULT MCI_read (unsigned char*, unsigned long, unsigned char); +DRESULT MCI_write (const unsigned char*, unsigned long, unsigned char); +DRESULT MCI_ioctl (unsigned char, void*); +void MCI_timerproc (void); + + +#endif diff --git a/drivers/include/flashrom.h b/drivers/include/flashrom.h new file mode 100644 index 000000000..c4fafc9e7 --- /dev/null +++ b/drivers/include/flashrom.h @@ -0,0 +1,27 @@ +#ifndef FLASHROM_H +#define FLASHROM_H + +#include +#include + +/* + * @brief Erase sector + * + * @param addr Address within a flash sector to erase + * + * @return 1 on success, 0 otherwise + */ +uint8_t flashrom_erase(uint8_t *addr); + +/* @brief Write buffer from ram to flash + * + * @param dst Address within a flash sector to write, must be a 256 byte boundary + * @param src Address within ram, must be a word boundary + * @param size Bytes to write + * + * @return 1 on success, 0 otherwise + */ +uint8_t flashrom_write(uint8_t *dst, char *src, size_t size); + + +#endif /* FLASHROM_H */ diff --git a/drivers/include/gpioint.h b/drivers/include/gpioint.h index 66cf138a6..8d5d30f1e 100644 --- a/drivers/include/gpioint.h +++ b/drivers/include/gpioint.h @@ -68,6 +68,7 @@ and the mailinglist (subscription via web site) #define GPIOINT_DISABLE 0x00 #define GPIOINT_RISING_EDGE 0x01 ///< interrupt is generated on rising edge #define GPIOINT_FALLING_EDGE 0x02 ///< interrupt is generated on falling edge +#define GPIOINT_DEBOUNCE 0x04 ///< debounce this interrupt /** * @brief GPIO IRQ callback function type diff --git a/drivers/include/ltc4150.h b/drivers/include/ltc4150.h index e7fbad663..fdc08573a 100644 --- a/drivers/include/ltc4150.h +++ b/drivers/include/ltc4150.h @@ -8,7 +8,10 @@ void ltc4150_start(); void ltc4150_stop(); double ltc4150_get_current_mA(); -double ltc4150_get_total_mA(); +double ltc4150_get_total_mAh(); +double ltc4150_get_total_Joule(void); double ltc4150_get_avg_mA(); +int ltc4150_get_interval(); +long ltc4150_get_intcount(void); #endif /* __LTC4150_H */ diff --git a/drivers/include/ltc4150_arch.h b/drivers/include/ltc4150_arch.h index 1a6c5c630..51fc9478a 100644 --- a/drivers/include/ltc4150_arch.h +++ b/drivers/include/ltc4150_arch.h @@ -46,6 +46,7 @@ and the mailinglist (subscription via web site) #define _GFH (double)32.631375 #define _R_SENSE (double)0.330 +#define SUPPLY_VOLTAGE (5) void ltc4150_disable_int(void); void ltc4150_enable_int(void); diff --git a/drivers/include/rtc.h b/drivers/include/rtc.h new file mode 100644 index 000000000..b40b72b50 --- /dev/null +++ b/drivers/include/rtc.h @@ -0,0 +1,63 @@ +/****************************************************************************** +Copyright 2010, Freie Universitaet Berlin (FUB). All rights reserved. + +These sources were developed at the Freie Universitaet Berlin, Computer Systems +and Telematics group (http://cst.mi.fu-berlin.de). +------------------------------------------------------------------------------- +This file is part of µkleos. + +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +FeuerWare is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see http://www.gnu.org/licenses/ . +-------------------------------------------------------------------------------- +For further information and questions please use the web site + http://scatterweb.mi.fu-berlin.de +and the mailinglist (subscription via web site) + scatterweb@lists.spline.inf.fu-berlin.de +*******************************************************************************/ + +#ifndef RTC_H +#define RTC_H + +#define RTC_SECOND 10001U + +#include + +/** + * @brief Initializes the RTC for calendar mode + */ +void rtc_init(void); + +/** + * @brief Starts the RTC + */ +void rtc_enable(void); + +/** + * @brief Stops the RTC + */ +void rtc_disable(void); + +/** + * @brief Sets the current time in broken down format directly from to RTC + * @param[in] localt Pointer to structure with time to set + */ +void rtc_set_localtime(struct tm* localt); + +/** + * @brief Returns the current time in broken down format directly from the RTC + * @param[out] localt Pointer to structure to receive time + */ +void rtc_get_localtime(struct tm* localt); + +extern int rtc_second_pid; + +#endif diff --git a/drivers/include/sht11.h b/drivers/include/sht11.h index d8db77602..227569f5e 100644 --- a/drivers/include/sht11.h +++ b/drivers/include/sht11.h @@ -40,6 +40,7 @@ and the mailinglist (subscription via web site) * * @note $Id: sht11.h 667 2009-02-19 15:06:38Z baar $ */ +#include #define SHT11_NO_ACK (0) #define SHT11_ACK (1) @@ -50,8 +51,12 @@ and the mailinglist (subscription via web site) #define SHT11_MEASURE_HUMI (0x05) //000 0010 1 #define SHT11_RESET (0x1E) //000 1111 0 -/** - * set measurement timeout to 1 second */ +/* time to wait after toggling the data line */ +#define SHT11_DATA_WAIT (HWTIMER_TICKS(1)) +/* time to wait after toggling the clock line */ +#define SHT11_CLK_WAIT (HWTIMER_TICKS(1)) + +/* set measurement timeout to 1 second */ #define SHT11_MEASURE_TIMEOUT (1000) /** diff --git a/drivers/ltc4150.c b/drivers/ltc4150.c index bcc166b70..9f4134b5c 100644 --- a/drivers/ltc4150.c +++ b/drivers/ltc4150.c @@ -46,14 +46,18 @@ static unsigned int last_int_time; static unsigned int last_int_duration; static unsigned int start_time; -static double int_to_coulomb(int ints) { +static double __attribute__((__no_instrument_function__)) int_to_coulomb(int ints) { return ((double)ints) / (_GFH * _R_SENSE); } -static double coulomb_to_mA(double coulomb){ +static double __attribute__((__no_instrument_function__)) coulomb_to_mA(double coulomb){ return (coulomb * 1000) / 3600; } +static double mAh_to_Joule(double mAh) { + return (SUPPLY_VOLTAGE * mAh * 3600); +} + uint32_t ltc4150_get_last_int_duration_us() { return HWTIMER_TICKS_TO_US(last_int_duration); } @@ -62,15 +66,23 @@ double ltc4150_get_current_mA() { return 1000000000/(ltc4150_get_last_int_duration_us()*(_GFH * _R_SENSE)); } -double ltc4150_get_total_mA() { +double __attribute__((__no_instrument_function__)) ltc4150_get_total_mAh() { return coulomb_to_mA(int_to_coulomb(int_count)); } +double ltc4150_get_total_Joule(void) { + return mAh_to_Joule(ltc4150_get_total_mAh()); +} + double ltc4150_get_avg_mA() { return (int_to_coulomb(int_count)*1000000000)/HWTIMER_TICKS_TO_US(last_int_time - start_time); } -unsigned long ltc4150_get_intcount() { +int ltc4150_get_interval() { + return HWTIMER_TICKS_TO_US(last_int_time - start_time); +} + +unsigned long __attribute__((__no_instrument_function__)) ltc4150_get_intcount() { return int_count; } @@ -92,7 +104,7 @@ void ltc4150_stop() { ltc4150_disable_int(); } -void ltc4150_interrupt() +void __attribute__((__no_instrument_function__)) ltc4150_interrupt() { uint32_t now = hwtimer_now(); if (now >= last_int_time) { diff --git a/drivers/sht11.c b/drivers/sht11.c index b0d77e03a..c81cfc56b 100644 --- a/drivers/sht11.c +++ b/drivers/sht11.c @@ -37,7 +37,6 @@ and the mailinglist (subscription via web site) * @note $Id: sht11.c 2396 2010-07-06 15:12:35Z ziegert $ */ -#include #include #include @@ -45,6 +44,12 @@ and the mailinglist (subscription via web site) #include #include #include +#include + +//#define ENABLE_DEBUG (1) +#include + +float sht11_temperature_offset; /** * @brief Perform measurement @@ -147,6 +152,7 @@ static uint8_t read_byte (uint8_t ack) value = value << 1; SHT11_SCK_HIGH; hwtimer_wait(SHT11_CLK_WAIT); + if (SHT11_DATA) { /* increase data by one when DATA is high */ value++; @@ -230,10 +236,10 @@ static uint8_t measure(uint8_t *p_value, uint8_t *p_checksum, uint8_t mode) uint8_t ack = 1; uint16_t i; - transmission_start(); + transmission_start(); error = write_byte(mode); - hwtimer_wait(HWTIMER_MSEC); + hwtimer_wait(HWTIMER_TICKS(1000)); /* wait untile sensor has finished measurement or timeout */ for (i = 0; (i < SHT11_MEASURE_TIMEOUT) && (!error); i++) { @@ -242,7 +248,7 @@ static uint8_t measure(uint8_t *p_value, uint8_t *p_checksum, uint8_t mode) if (!ack) { break; } - hwtimer_wait(HWTIMER_MSEC); + hwtimer_wait(HWTIMER_TICKS(1000)); } error += ack; @@ -257,9 +263,10 @@ static uint8_t measure(uint8_t *p_value, uint8_t *p_checksum, uint8_t mode) } /*---------------------------------------------------------------------------*/ void sht11_init(void) { + sht11_temperature_offset = 0; mutex_init(&sht11_mutex); SHT11_INIT; - hwtimer_wait(11 * HWTIMER_MSEC); + hwtimer_wait(11 * HWTIMER_TICKS(1000)); } /*---------------------------------------------------------------------------*/ uint8_t sht11_read_status(uint8_t *p_value, uint8_t *p_checksum) { @@ -303,7 +310,9 @@ uint8_t sht11_read_sensor(sht11_val_t *value, sht11_mode_t mode) { const float T2 = +0.00008; /* check for valid buffer */ - assert(value != NULL); + if (value == NULL) { + return 0; + } value->temperature = 0; value->relhum = 0; @@ -329,7 +338,7 @@ uint8_t sht11_read_sensor(sht11_val_t *value, sht11_mode_t mode) { } if (mode & TEMPERATURE) { - value->temperature = D1 + (D2 * ((float) temp_int)); + value->temperature = D1 + (D2 * ((float) temp_int)) + sht11_temperature_offset; } if (mode & HUMIDITY) { value->relhum = C1 + (C2 * ((float) humi_int)) + (C3 * ((float) humi_int) * ((float) humi_int)); diff --git a/projects/WEAtHeR/Jamfile b/projects/WEAtHeR/Jamfile new file mode 100644 index 000000000..4974b6d04 --- /dev/null +++ b/projects/WEAtHeR/Jamfile @@ -0,0 +1,5 @@ +SubDir TOP projects WEAtHeR ; + +Module WEAtHeR : main.c weather_routing.c protocol_msg_gateway.c : ltc4150 cc110x gpioint vtimer shell shell_commands posix_io uart0 auto_init rtc ; + +UseModule WEAtHeR ; diff --git a/projects/WEAtHeR/main.c b/projects/WEAtHeR/main.c new file mode 100644 index 000000000..b562d334c --- /dev/null +++ b/projects/WEAtHeR/main.c @@ -0,0 +1,347 @@ +/* stdlib includes */ +#include +#include +#include +#include + +/* core includes */ +#include +#include +#include + +#define ENABLE_DEBUG +#include + +/* sensors and actors */ +#include +#include +#include + +/* shell */ +#include +#include +#include + +/* transceiver */ +#include + +/* real time clock */ +#include +#include + +/* application header */ +#include "weather_routing.h" +#include "weather_protocol.h" +#include "protocol_msg_gateway.h" + +#define SECOND (1000 * 1000) +#define MINUTE (60 * SECOND) + +#define SENDING_INTERVAL (1 * SECOND) + +#define SHELL_STACK_SIZE (2048) +#define PH_STACK_SIZE (2048) + +/* size of weather data packet without hop list */ +#define EMPTY_WDP_SIZE (sizeof(weather_data_pkt_t) - MAX_HOP_LIST) + +/* default values */ +#define DEFAULT_INTERVAL (5 * SECOND) + +/* stack space for threads */ +#define SHELL_STACK_SIZE (4048) +#define PH_STACK_SIZE (4048) + +char shell_stack_buffer[SHELL_STACK_SIZE]; +char ph_stack_buffer[PH_STACK_SIZE]; + +/* per default acting only as relay */ +static uint8_t data_sink = 0; +static uint8_t data_src = 0; + +static uint32_t sending_interval = DEFAULT_INTERVAL; + +extern uint8_t gossip_probability; + +/* function prototypes */ +static void weather_send(char* unused); +static void weather_sink(char* unused); +static void set_interval(char* interval); +static void set_probability(char* prob); +static void print_cc1100_info(char* unused); + +/* shell commands */ +shell_t shell; +const shell_command_t sc[] = { + {"sender", "Enables node as data source.", weather_send}, + {"sink", "Enables node as data sink.", weather_sink}, + {"int", "Set the sending interval in seconds", set_interval}, + {"prob", "Set the gossiping probability", set_probability}, + {"cc1100", "Show state, statistics and config of cc1100", print_cc1100_info}, + {NULL, NULL, NULL}}; + +static void shell_runner(void) { + shell_init(&shell, sc, uart0_readc, uart0_putc); + posix_open(uart0_handler_pid, 0); + shell_run(&shell); +} + +static void weather_send(char* unused) { + if (data_src) { + data_src = 0; + puts("Disabling data source mode."); + } + else { + data_src = 1; + puts("Enabling data source mode."); + } +} + +static void weather_sink(char* unused) { + if (data_sink) { + data_sink = 0; + puts("Disabling data sink mode."); + } + else { + data_sink = 1; + puts("Enabling data sink mode."); + } +} + +static void set_interval(char* interval) { + uint16_t a; + + a = atoi(interval+4); + if (strlen(interval) > 4) { + printf("[WEAtHeR] Set interval to %u\n ", a); + sending_interval = a * SECOND; + } + else { + printf("[WEAtHeR] Current interval is %lu\n ", (sending_interval / SECOND)); + } +} + +static void set_probability(char* prob) { + uint16_t a; + + a = atoi(prob+4); + if (strlen(prob) > 4) { + printf("[WEAtHeR] Set probability to %hu\n ", a); + gossip_probability = a; + } + else { + printf("[WEAtHeR] Current probability is %hu\n ", gossip_probability); + } +} + +static void print_cc1100_info(char* unused) { + puts("=================================================="); + cc1100_print_statistic(); + puts("--------------------------------------------------"); + cc1100_print_config(); + puts("=================================================="); +} + +/* packet handling */ +static void handle_packet(void* msg, int msg_size, packet_info_t* packet_info) { + weather_packet_header_t *header = (weather_packet_header_t*) msg; + + /* packet origins at current node, just ignore it */ + if (header->src == cc1100_get_address()) { + return; + } + DEBUG("\n\t Pkt received from phy: %u (%u bytes)\n" + "\t -> SEQ: %u | TYPE: %u | SRC: %hu \n\n", + packet_info->phy_src, + msg_size, + header->seq_nr, + header->type, + header->src + ); + /* while not acting as sink and packet contains data, route the packet */ + if (!data_sink) { + if (header->type == WEATHER_DATA) { + weather_data_pkt_t* wdp = (weather_data_pkt_t*) msg; + DEBUG("$0;%hu;%hu;%04lX;%04X;%.2f;%.2f;%.2f;%.2f\n", + header->src, + 0, + wdp->timestamp, + 0, + wdp->temperature, + wdp->relhum, + wdp->relhum_temp, + wdp->energy); + DEBUG("Not for me, routing, baby!\n"); + route_packet(msg, msg_size); + } + + return; + } + + /* if current node acts as sink, handle packet */ + switch (header->type) { + case WEATHER_HELLO: { + if (msg_size < sizeof(weather_hello_pkt_t)) { + puts("Bad hello packet received."); + } else { + puts("Hello packet received - no handler implemented"); + } + break; + } + case WEATHER_CHAT: { + puts("\n*================================================================================*"); + printf("\tCHAT MESSAGE from %hu: %s\n\n", packet_info->phy_src, ((weather_chat_pkt_t*) msg)->mesg); + puts("*================================================================================*\n"); + break; + } + case WEATHER_DATA: { + weather_data_pkt_t* wdp = (weather_data_pkt_t*) msg; + uint8_t i; + time_t local_time = rtc_time(NULL); + /* ;;;;;;; */ + printf("$1;%hu;%u;%04lX;%04lX;%.2f;%.2f;%.2f;%.2f;", + header->src, + cc1100_get_address(), + wdp->timestamp, + local_time, + wdp->temperature, + wdp->relhum, + wdp->relhum_temp, + wdp->energy); + for (i = 0; i < wdp->hop_counter; i++) { + printf("%03u-", wdp->hops[i]); + } + puts(""); + break; + } + default: { + printf("Unknown packet type \"%i\" received.\n", header->type); + } + } +} + +/* endless loop for packet handling */ +static void protocol_handler_thread(void) { + msg_t m; + puts("Protocol handler thread started."); + + while(1) { + msg_receive(&m); + + packet_t packet; + int pos = m.content.value; + packet = packet_buffer[pos]; + + handle_packet(packet.payload, packet.msg_size, &(packet.packet_info)); + DEBUG("Packet handler done\n"); + } +} + +int main(void) { + weather_data_pkt_t wdp; + sht11_val_t sht11_val; + + /* initialize variables */ + uint8_t success = 0; + int sending_state = 0; + gossip_probability = FLOODING_PROB; + + /* fill some fields of the packet */ + wdp.header.seq_nr = 0; + wdp.header.type = WEATHER_DATA; + wdp.hop_counter = 1; + + /* set initial channel */ + cc1100_set_channel(10); + + /* boot screen */ + puts(""); + puts("WEAtHeR: Wireless Energy-Aware mulTi-Hop sEnsor Reading."); + puts(""); + printf("Sending interval: %lu\n", sending_interval / SECOND); + + /* start shell */ + thread_create(shell_stack_buffer, SHELL_STACK_SIZE, PRIORITY_MAIN-1, CREATE_STACKTEST, shell_runner, "shell"); + + /* initialize message gateway */ + init_protocol_msg_gateway(); + /* create thread for radio packet handling */ + int pid = thread_create(ph_stack_buffer, PH_STACK_SIZE, PRIORITY_MAIN-2, CREATE_STACKTEST, protocol_handler_thread, "protocol_handler"); + set_protocol_handler_thread(pid); + + /* start coulomb counter and RTC */ + ltc4150_start(); + rtc_enable(); + + /* loop forever */ + while (1) { + DEBUG("Measurement in progress...\n"); +#ifndef ENABLE_DEBUG + success = sht11_read_sensor(&sht11_val, HUMIDITY|TEMPERATURE); +#else + success = 1; + sht11_val.temperature = 1; + sht11_val.relhum = 2; + sht11_val.relhum_temp = 3; +#endif + DEBUG("...done.\n"); + + if (data_src) { + wdp.header.src = cc1100_get_address(); + DEBUG("Src filled\n"); + wdp.timestamp = rtc_time(NULL); + DEBUG("Timestamp filled\n"); + wdp.energy = ltc4150_get_total_mAh(); + DEBUG("Energy filled\n"); + + if (!success) { + printf("error;error;error\n"); + } + else { + wdp.temperature = sht11_val.temperature; + wdp.relhum = sht11_val.relhum; + wdp.relhum_temp = sht11_val.relhum_temp; + wdp.hops[0] = cc1100_get_address(); + DEBUG("Ready for sending\n"); + /* send packet with one entry in hop list */ + sending_state = cc1100_send_csmaca(0, WEATHER_PROTOCOL_NR, 0, (char*)&wdp, (EMPTY_WDP_SIZE + 1)); + if (sending_state > 0) { + DEBUG("Sending %lu bytes.\n", (EMPTY_WDP_SIZE + 1)); + wdp.header.seq_nr++; + } + else { + printf("Error on sending packet with code %i!\n", sending_state); + } + } + LED_GREEN_TOGGLE; + } + else { + LED_RED_TOGGLE; + } + + if (!success) { + printf("error;error;error\n"); + } + else { +#ifdef ENABLE_DEBUG + puts("=================================================="); + cc1100_print_statistic(); + puts("--------------------------------------------------"); + cc1100_print_config(); + puts("=================================================="); +#endif + + printf("$0;%hu;%hu;%04lX;%04X;%.2f;%.2f;%.2f;%.2f\n", + cc1100_get_address(), + 0, + rtc_time(NULL), + 0, + sht11_val.temperature, + sht11_val.relhum, + sht11_val.relhum_temp, + ltc4150_get_total_mAh()); + } + hwtimer_wait(sending_interval); + } + puts("Something went wrong."); +} diff --git a/projects/WEAtHeR/protocol_msg_gateway.c b/projects/WEAtHeR/protocol_msg_gateway.c new file mode 100644 index 000000000..baccab5e9 --- /dev/null +++ b/projects/WEAtHeR/protocol_msg_gateway.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include "protocol_msg_gateway.h" +#include "weather_protocol.h" + +#define NUM_PROTOCOL_HANDLER_PIDS 8 + +static uint16_t protocol_handler_pid; + +static int packet_buffer_next = 0; +packet_t packet_buffer[PACKET_BUFFER_SIZE]; + +static void protocol_msg_gateway(void* payload, int msg_size, packet_info_t* packet_info) { + msg_t m; + + if (!cc1100_get_address()) { + puts("No address configured, not processing incoming packet"); + return; + } + + if (protocol_handler_pid <= 0) { + puts("protocol_handler(): received packet without protocol handler. msg dropped."); + return; + } + + int mypos = packet_buffer_next++; + if (packet_buffer_next == PACKET_BUFFER_SIZE) packet_buffer_next = 0; + + packet_t *p = &(packet_buffer[mypos]); + p->packet_info = *packet_info; + p->msg_size = msg_size; + memcpy(p->payload, payload, msg_size); + + m.type = 0; + m.content.value = mypos; + int success = msg_send_int(&m, protocol_handler_pid); + if (! success) { + /* should set timer to retry. Dropping pkt for now. */ + puts("protocol_handler(): msg dropped."); + } +} + +void init_protocol_msg_gateway() { + puts("Init protocol msg gateway"); + cc1100_set_packet_handler(WEATHER_PROTOCOL_NR, protocol_msg_gateway); +} + +int set_protocol_handler_thread(int pid) { + protocol_handler_pid = pid; + return 0; +} diff --git a/projects/WEAtHeR/protocol_msg_gateway.h b/projects/WEAtHeR/protocol_msg_gateway.h new file mode 100644 index 000000000..dd190da99 --- /dev/null +++ b/projects/WEAtHeR/protocol_msg_gateway.h @@ -0,0 +1,18 @@ +#ifndef __PROTOCOL_MSG_GATEWAY_H +#define __PROTOCOL_MSG_GATEWAY_H + +#define PACKET_BUFFER_SIZE 32 +#define MAXIMUM_PAYLOAD_SIZE 64 + +typedef struct { + packet_info_t packet_info; + unsigned int msg_size; + char payload[MAXIMUM_PAYLOAD_SIZE]; +} packet_t; + +void init_protocol_msg_gateway(); +int set_protocol_handler_thread(int pid); + +extern packet_t packet_buffer[PACKET_BUFFER_SIZE]; + +#endif /* __PROTOCOL_MSG_GATEWAY_H */ diff --git a/projects/WEAtHeR/tests/hello-world b/projects/WEAtHeR/tests/hello-world new file mode 100755 index 000000000..acde8265f --- /dev/null +++ b/projects/WEAtHeR/tests/hello-world @@ -0,0 +1,13 @@ +#!/usr/bin/expect + +set timeout 5 + +spawn pseudoterm $env(PORT) + +expect { + "Hello World!" {} + timeout { exit 1 } +} + +puts "\nTest successful!\n" + diff --git a/projects/WEAtHeR/weather_protocol.h b/projects/WEAtHeR/weather_protocol.h new file mode 100644 index 000000000..8785fd026 --- /dev/null +++ b/projects/WEAtHeR/weather_protocol.h @@ -0,0 +1,43 @@ +#ifndef WEATHER_PROTOCOL_H_ +#define WEATHER_PROTOCOL_H_ + +#include +#include + +#define WEATHER_PROTOCOL_NR 6 +#define MAX_HOP_LIST (11) + +typedef enum { + WEATHER_HELLO, + WEATHER_CHAT, + WEATHER_DATA +} packet_types; + +typedef struct { + uint16_t seq_nr; + uint8_t src; + uint8_t type; +} weather_packet_header_t; + +typedef struct __attribute__ ((packed)) { + weather_packet_header_t header; +} weather_hello_pkt_t; + +typedef struct { + weather_packet_header_t header; + uint8_t len; + char mesg[40]; +} weather_chat_pkt_t; + +typedef struct __attribute__ ((packed)) { + weather_packet_header_t header; + time_t timestamp; + double temperature; + double relhum; + double relhum_temp; + double energy; + uint8_t hop_counter; + uint8_t hops[MAX_HOP_LIST]; +} weather_data_pkt_t; + +#endif diff --git a/projects/WEAtHeR/weather_routing.c b/projects/WEAtHeR/weather_routing.c new file mode 100644 index 000000000..3e572a96c --- /dev/null +++ b/projects/WEAtHeR/weather_routing.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include + +#include "weather_protocol.h" +#include "weather_routing.h" + +#define ENABLE_DEBUG +#include + +uint8_t gossip_probability; + +static source_timestamp_t sources[MAX_SOURCES]; + +static uint8_t update_sources(uint8_t id, time_t timestamp) { + uint8_t i; + + DEBUG("updating sources list\n"); + for (i = 0; i < MAX_SOURCES; i++) { + /* source id found */ + if (sources[i].id == id) { + DEBUG("source already known, comparing timestamps: %04lX : %04lX\n", sources[i].timestamp, timestamp); + /* more current timestamp received, updating */ + if (sources[i].timestamp < timestamp) { + sources[i].timestamp = timestamp; + return 1; + } + /* timestamp too old, discard this packet */ + else { + puts("Timestamp too old, not routing"); + return 0; + } + } + /* source id not yet stored creating new entry */ + else if (!sources[i].id) { + puts("got to know a new source"); + sources[i].id = id; + sources[i].timestamp = timestamp; + return 1; + } + } + puts("No more sources could be stored!"); + return 0; +} + +void route_packet(void* msg, int msg_size) { + weather_packet_header_t *header = (weather_packet_header_t*) msg; + weather_data_pkt_t* wdp = NULL; + int state = 0; + + if (header->type == WEATHER_DATA) { + wdp = (weather_data_pkt_t*) msg; + if (!update_sources(wdp->header.src, wdp->timestamp)) { + return; + } + } + + if ((100.0 * rand()/(double) RAND_MAX) <= gossip_probability) { + printf("Broadcasting packet..."); + /* if broadcasting weather data, append current hop */ + if (wdp != NULL) { + if (wdp->hop_counter < MAX_HOP_LIST) { + wdp->hops[wdp->hop_counter] = cc1100_get_address(); + wdp->hop_counter++; + } + } + state = cc1100_send_csmaca(0, WEATHER_PROTOCOL_NR, 0, (char*)msg, msg_size); + if (state > 0) { + puts("successful!"); + } + else { + printf("failed with code %i!\n", state); + } + } +} + diff --git a/projects/WEAtHeR/weather_routing.h b/projects/WEAtHeR/weather_routing.h new file mode 100644 index 000000000..14d050177 --- /dev/null +++ b/projects/WEAtHeR/weather_routing.h @@ -0,0 +1,17 @@ +#ifndef WEATHER_ROUTING_H +#define WEATHER_ROUTING_H + +#include + +#define FLOODING_PROB (100) +#define MAX_SOURCES (10) +#define MAX_INTERVAL (5 * 60) + +typedef struct { + uint8_t id; + time_t timestamp; +} source_timestamp_t; + +void route_packet(void* msg, int msg_size); + +#endif /* WEATHER_ROUTING_H */ diff --git a/projects/cc110x/main.c b/projects/cc110x/main.c index 8e350703e..59a91c2c8 100644 --- a/projects/cc110x/main.c +++ b/projects/cc110x/main.c @@ -58,7 +58,7 @@ int main(void) // radio stack cc1100_init(); cc1100_set_packet_handler(4, protocol_handler); - cc1100_set_channel(10); + cc1100_set_channel(0); // cc1100_set_output_power(5); printf("cc1100..[OK]\n"); @@ -68,11 +68,12 @@ int main(void) cc1100_set_address(2); - while(1) { +// while(1) { puts("."); int result = cc1100_send_csmaca(1, 4, 2, i, sizeof(i)); printf("%i\n", result); - } + hwtimer_wait(1000 * 1000); +// } #else cc1100_set_address(1); while(1) { diff --git a/projects/chronos_cc110x_ng/Jamfile b/projects/chronos_cc110x_ng/Jamfile new file mode 100644 index 000000000..8085574cb --- /dev/null +++ b/projects/chronos_cc110x_ng/Jamfile @@ -0,0 +1,5 @@ +SubDir TOP projects chronos_cc110x_ng ; + +Module chronos_cc110x_ng : main.c : cc110x_ng transceiver auto_init board_display ; + +UseModule chronos_cc110x_ng ; diff --git a/projects/chronos_cc110x_ng/main.c b/projects/chronos_cc110x_ng/main.c new file mode 100644 index 000000000..4d19a3422 --- /dev/null +++ b/projects/chronos_cc110x_ng/main.c @@ -0,0 +1,101 @@ +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#define RADIO_STACK_SIZE (512) +#define SEND_SIZE CC1100_MAX_DATA_LENGTH + +#define RCV_BUFFER_SIZE (4) + +#define SENDING_DELAY (5 * 1000) + +char radio_stack_buffer[RADIO_STACK_SIZE]; + +uint8_t snd_buffer[SEND_SIZE]; + +msg_t msg_q[RCV_BUFFER_SIZE]; + +static msg_t mesg; +static transceiver_command_t tcmd; +static radio_packet_t p; + +void send(radio_address_t dst, uint8_t len, uint8_t *data); + +void send(radio_address_t dst, uint8_t len, uint8_t *data) { + mesg.type = SND_PKT; + mesg.content.ptr = (char*) &tcmd; + + tcmd.transceivers = TRANSCEIVER_CC1100; + tcmd.data = &p; + + p.length = len; + p.dst = dst; + display_chars(LCD_SEG_L2_5_0, "CC1100", SEG_OFF); + display_chars(LCD_SEG_L2_5_0, (char*) itoa(p.dst, 6, 0), SEG_ON); + + p.data = data; + msg_send(&mesg, transceiver_pid, 1); +} + + +void radio(void) { + msg_t m; + radio_packet_t *p; + + msg_init_queue(msg_q, RCV_BUFFER_SIZE); + + while (1) { + msg_receive(&m); + if (m.type == PKT_PENDING) { + + p = (radio_packet_t*) m.content.ptr; + display_chars(LCD_SEG_L2_5_0, "CC1100", SEG_OFF); + display_chars(LCD_SEG_L2_5_0, (char*) p->data, SEG_ON); + send(p->src, p->length, p->data); + + + p->processing--; + } + else if (m.type == ENOBUFFER) { + } + else { + } + } +} + +int main(void) { + int radio_pid; + + radio_address_t addr = 43; + memset(snd_buffer, 43, SEND_SIZE); + radio_pid = thread_create(radio_stack_buffer, RADIO_STACK_SIZE, PRIORITY_MAIN-2, CREATE_STACKTEST, radio, "radio"); + transceiver_init(TRANSCEIVER_CC1100); + transceiver_start(); + transceiver_register(TRANSCEIVER_CC1100, radio_pid); + + lcd_init(); + clear_display_all(); + mesg.type = SET_ADDRESS; + mesg.content.ptr = (char*) &tcmd; + + display_chars(LCD_SEG_L2_5_0, "CC1100", SEG_ON); + tcmd.transceivers = TRANSCEIVER_CC1100; + tcmd.data = &addr; + msg_send(&mesg, transceiver_pid, 1); + + send(0, SEND_SIZE, snd_buffer); + + while (1) { + hwtimer_wait(SENDING_DELAY); + display_chars(LCD_SEG_L1_3_0, itoa(hwtimer_now(), 4, 0), SEG_ON); + } +} diff --git a/projects/chronos_cc110x_ng/tests/hello-world b/projects/chronos_cc110x_ng/tests/hello-world new file mode 100755 index 000000000..acde8265f --- /dev/null +++ b/projects/chronos_cc110x_ng/tests/hello-world @@ -0,0 +1,13 @@ +#!/usr/bin/expect + +set timeout 5 + +spawn pseudoterm $env(PORT) + +expect { + "Hello World!" {} + timeout { exit 1 } +} + +puts "\nTest successful!\n" + diff --git a/projects/chronos_default/Jamfile b/projects/chronos_default/Jamfile new file mode 100644 index 000000000..0e68768aa --- /dev/null +++ b/projects/chronos_default/Jamfile @@ -0,0 +1,5 @@ +SubDir TOP projects chronos_default ; + +Module chronos_default : main.c altitude.c : transceiver cc110x_ng rtc board_buzzer board_display auto_init gpioint display_putchar battery vti_ps ; + +UseModule chronos_default ; diff --git a/projects/chronos_default/main.c b/projects/chronos_default/main.c new file mode 100644 index 000000000..8189f3fd5 --- /dev/null +++ b/projects/chronos_default/main.c @@ -0,0 +1,167 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "altitude.h" + +#define BUTTON_EVENT_STAR (0x01) +#define BUTTON_EVENT_NUM (0x02) +#define BUTTON_EVENT_UP (0x04) +#define BUTTON_EVENT_DOWN (0x08) +#define BUTTON_EVENT_BACKLIGHT (0x10) + +#define BUTTON_HANDLER_STACK_SIZE (256) +#define RADIO_STACK_SIZE (512) +#define SEND_SIZE CC1100_MAX_DATA_LENGTH + +#define RCV_BUFFER_SIZE (4) + +#define SENDING_DELAY (5 * 1000) + +char radio_stack_buffer[RADIO_STACK_SIZE]; +char button_handler_stack_buffer[BUTTON_HANDLER_STACK_SIZE]; + +uint8_t snd_buffer[SEND_SIZE]; + +msg_t msg_q[RCV_BUFFER_SIZE]; + +static msg_t mesg; +static transceiver_command_t tcmd; +static radio_packet_t p; + +static int button_handler_pid; +static uint8_t button_event = 0; +static uint8_t mode = 0; + +void send(radio_address_t dst, uint8_t len, uint8_t *data); + +void send(radio_address_t dst, uint8_t len, uint8_t *data) { + mesg.type = SND_PKT; + mesg.content.ptr = (char*) &tcmd; + + tcmd.transceivers = TRANSCEIVER_CC1100; + tcmd.data = &p; + + p.length = len; + p.dst = dst; + + p.data = data; + msg_send(&mesg, transceiver_pid, 1); +} + +void radio(void) { + msg_t m; + radio_packet_t *p; + + msg_init_queue(msg_q, RCV_BUFFER_SIZE); + + while (1) { + msg_receive(&m); + if (m.type == PKT_PENDING) { + + p = (radio_packet_t*) m.content.ptr; + send(p->src, p->length, p->data); + + p->processing--; + } + else if (m.type == ENOBUFFER) { + } + else { + } + } +} + +void button_handler(void) { + while (1) { + if (button_event & BUTTON_EVENT_STAR) { + buzzer_beep(15, 5000); + mode++; + button_event &= ~BUTTON_EVENT_STAR; + } + thread_sleep(); + } +} + +void change_mode(void) { + button_event |= BUTTON_EVENT_STAR; + thread_wakeup(button_handler_pid); +} + +int main(void) { + int radio_pid; + uint32_t voltage; + struct tm now; + + ps_init(); + reset_altitude_measurement(); + + now.tm_hour = 3; + now.tm_min = 59; + now.tm_sec = 42; + + rtc_set_localtime(&now); + + now.tm_min = 6; + + rtc_set_alarm(&now, RTC_ALARM_MIN); + + button_handler_pid = thread_create(button_handler_stack_buffer, BUTTON_HANDLER_STACK_SIZE, PRIORITY_MAIN+1, CREATE_STACKTEST, button_handler, "button_handler"); + gpioint_set(2, BUTTON_STAR_PIN, (GPIOINT_RISING_EDGE | GPIOINT_DEBOUNCE), change_mode); + + radio_address_t addr = 43; + memset(snd_buffer, 43, SEND_SIZE); + /* + radio_pid = thread_create(radio_stack_buffer, RADIO_STACK_SIZE, PRIORITY_MAIN-2, CREATE_STACKTEST, radio, "radio"); + transceiver_init(TRANSCEIVER_CC1100); + transceiver_start(); + transceiver_register(TRANSCEIVER_CC1100, radio_pid); + + mesg.type = SET_ADDRESS; + mesg.content.ptr = (char*) &tcmd; + + printf("CC430"); + tcmd.transceivers = TRANSCEIVER_CC1100; + tcmd.data = &addr; + msg_send(&mesg, transceiver_pid, 1); + + send(12, SEND_SIZE, snd_buffer); +*/ + while (1) { + hwtimer_wait(SENDING_DELAY); + rtc_get_localtime(&now); + + voltage = battery_get_voltage(); + switch (mode) { + case 0: + printf("\n%lu", voltage); + break; + case 1: + printf("\n%02u:%02u", now.tm_hour, now.tm_min); + break; + case 2: + start_altitude_measurement(); + printf("\n%u", sAlt.altitude); + stop_altitude_measurement(); + break; + default: + mode = 0; + break; + } + } +} diff --git a/projects/chronos_default/tests/hello-world b/projects/chronos_default/tests/hello-world new file mode 100755 index 000000000..acde8265f --- /dev/null +++ b/projects/chronos_default/tests/hello-world @@ -0,0 +1,13 @@ +#!/usr/bin/expect + +set timeout 5 + +spawn pseudoterm $env(PORT) + +expect { + "Hello World!" {} + timeout { exit 1 } +} + +puts "\nTest successful!\n" + diff --git a/projects/default/Jamfile b/projects/default/Jamfile new file mode 100644 index 000000000..bdbee91b6 --- /dev/null +++ b/projects/default/Jamfile @@ -0,0 +1,11 @@ +# +# ukleos default project. Consists of a shell. +# +# Copyright (C) 2008, 2009 Kaspar Schleiser +# + +SubDir TOP projects default ; + +Module default_project : main.c : shell posix_io uart0 shell_commands ps rtc sht11 ltc4150 cc110x_ng transceiver gpioint auto_init config mci ; + +UseModule default_project ; diff --git a/projects/default/main.c b/projects/default/main.c new file mode 100644 index 000000000..ccc4cfd9a --- /dev/null +++ b/projects/default/main.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2008, 2009, 2010 Kaspar Schleiser + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +int shell_readc() { + char c = 0; + posix_read(uart0_handler_pid, &c, 1); + return c; +} + +void shell_putchar(int c) { + putchar(c); +} + +int main(void) { + posix_open(uart0_handler_pid, 0); + ltc4150_start(); + transceiver_init(TRANSCEIVER_CC1100); + transceiver_start(); + + puts("Welcome to ukleos!"); + + shell_t shell; + shell_init(&shell, NULL, shell_readc, shell_putchar); + + shell_run(&shell); + return 0; +} + + diff --git a/projects/hi_earth/Jamfile b/projects/hi_earth/Jamfile index dd8a116f8..812f2c912 100644 --- a/projects/hi_earth/Jamfile +++ b/projects/hi_earth/Jamfile @@ -1,5 +1,5 @@ SubDir TOP projects hi_earth ; -Module hi_earth : main.c ; +Module hi_earth : main.c : auto_init display_putchar ; UseModule hi_earth ; diff --git a/projects/hi_earth/main.c b/projects/hi_earth/main.c index 46911bbea..fa70601b9 100644 --- a/projects/hi_earth/main.c +++ b/projects/hi_earth/main.c @@ -1,53 +1,9 @@ -//****************************************************************************** -// eZ430 chronos hello world -// Description: initializes lcd module and shows the string 'hi earth' on the -// lcd display becuase 'hello world' is too long -// Author: Felix Genicio -//****************************************************************************** - -#include "cc430x613x.h" -#include -#include - -void display1(void); -void display2(void); +#include int main(void) { - lcd_init(); - - clear_display_all(); - - uint8_t i = 0; - uint16_t j; + printf("Hi Earth\n"); while(1) { - if (i) { - i = 0; - display1(); - } - else { - i = 1; - display2(); - } - for (j = 1; j != 0; j++) { - if (i) { - display_symbol(LCD_ICON_BEEPER1, SEG_ON); - } - else { - display_symbol(5, SEG_OFF); - } - } } } - -void display1(void) { - display_chars(LCD_SEG_L1_3_0, (uint8_t*) "HI", SEG_ON); - display_chars(LCD_SEG_L2_5_0, (uint8_t*) " EARTH", SEG_OFF); -} - -void display2(void) { - display_chars(LCD_SEG_L1_3_0, (uint8_t*) "HI", SEG_OFF); - display_chars(LCD_SEG_L2_5_0, (uint8_t*) " EARTH", SEG_ON); -} - diff --git a/projects/laser/Jamfile b/projects/laser/Jamfile new file mode 100644 index 000000000..9a9c55950 --- /dev/null +++ b/projects/laser/Jamfile @@ -0,0 +1,5 @@ +SubDir TOP projects laser ; + +Module laser : main.c : sht11 ltc4150 swtimer auto_init ; + +UseModule laser ; diff --git a/projects/laser/main.c b/projects/laser/main.c new file mode 100644 index 000000000..e3c3d4f83 --- /dev/null +++ b/projects/laser/main.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include + +int main(void) +{ + sht11_val_t sht11_val; + double mAh = 0; + + uint8_t success = 0; + + puts(""); + puts("LaSeR: Longterm Sensor Reader initialized."); + puts("Printing \"temperature in °C;relative humidity;temperature compensated relative humidity\"."); + puts(""); + + ltc4150_start(); + + while (1) { + success = sht11_read_sensor(&sht11_val, HUMIDITY|TEMPERATURE); + mAh = ltc4150_get_total_mAh(); + if (!success) { + printf("error;error;error\n"); + } + else { + printf("%.2f;%.2f;%.2f;%.2f\n", sht11_val.temperature, sht11_val.relhum, sht11_val.relhum_temp, mAh); + } + LED_RED_TOGGLE; + swtimer_usleep(60 * 1000*1000); + } +} diff --git a/projects/msb430_cc110x_ng/Jamfile b/projects/msb430_cc110x_ng/Jamfile new file mode 100644 index 000000000..61234651e --- /dev/null +++ b/projects/msb430_cc110x_ng/Jamfile @@ -0,0 +1,5 @@ +SubDir TOP projects msb430_cc110x_ng ; + +Module msb430_cc110x_ng : main.c : cc110x_ng transceiver swtimer shell shell_commands ps posix_io uart0 auto_init config ; + +UseModule msb430_cc110x_ng ; diff --git a/projects/msb430_cc110x_ng/main.c b/projects/msb430_cc110x_ng/main.c new file mode 100644 index 000000000..60719ec14 --- /dev/null +++ b/projects/msb430_cc110x_ng/main.c @@ -0,0 +1,158 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SHELL_STACK_SIZE (512) +#define RADIO_STACK_SIZE (512) + +#define SND_BUFFER_SIZE (3) +#define RCV_BUFFER_SIZE (4) + +#define SENDING_DELAY (5 * 1000) + +char shell_stack_buffer[SHELL_STACK_SIZE]; +char radio_stack_buffer[RADIO_STACK_SIZE]; + +uint8_t snd_buffer[SND_BUFFER_SIZE][CC1100_MAX_DATA_LENGTH]; + +msg_t msg_q[RCV_BUFFER_SIZE]; + +static msg_t mesg; +static transceiver_command_t tcmd; +static radio_packet_t p; + +void sender(char *count); +void print_buffer(char *unused); + +shell_t shell; +const shell_command_t sc[] = { + {"snd", "", sender}, + {"buffer", "", print_buffer}, + {NULL, NULL, NULL} +}; + +void send(radio_address_t dst, uint8_t len, uint8_t *data); + +void send(radio_address_t dst, uint8_t len, uint8_t *data) { + mesg.type = SND_PKT; + mesg.content.ptr = (char*) &tcmd; + + tcmd.transceivers = TRANSCEIVER_CC1100; + tcmd.data = &p; + + p.length = len; + p.dst = dst; + + p.data = data; + msg_send(&mesg, transceiver_pid, 1); +} + +void shell_runner(void) { + shell_init(&shell, sc, uart0_readc, uart0_putc); + posix_open(uart0_handler_pid, 0); + shell_run(&shell); +} + + +void sender(char *count) { + unsigned int c = 3; + unsigned int i; + + mesg.type = SND_PKT; + mesg.content.ptr = (char*) &tcmd; + + tcmd.transceivers = TRANSCEIVER_CC1100; + tcmd.data = &p; + + p.length = CC1100_MAX_DATA_LENGTH; + p.dst = 0; + + for (i = 0; i < c; i++) { + puts("."); + p.data = snd_buffer[i % SND_BUFFER_SIZE]; + msg_send(&mesg, transceiver_pid, 1); + swtimer_usleep(SENDING_DELAY); + } +} + +void print_buffer(char *unused) { + uint8_t i; + extern radio_packet_t transceiver_buffer[]; + for (i = 0; i < TRANSCEIVER_BUFFER_SIZE; i++) { + printf("[%u] %u # %u # %u\n", i, transceiver_buffer[i].processing, transceiver_buffer[i].length, transceiver_buffer[i].data[i]); + } + extern rx_buffer_t cc1100_rx_buffer[]; + for (i = 0; i < TRANSCEIVER_BUFFER_SIZE; i++) { + printf("[%u] %u # %u \n", i, cc1100_rx_buffer[i].packet.length, cc1100_rx_buffer[i].packet.data[i]); + } +} + +void radio(void) { + msg_t m; + radio_packet_t *p; + uint8_t i; + + msg_init_queue(msg_q, RCV_BUFFER_SIZE); + + while (1) { + msg_receive(&m); + if (m.type == PKT_PENDING) { + p = (radio_packet_t*) m.content.ptr; + printf("Packet waiting, process %p...\n", p); + printf("\tLength:\t%u\n", p->length); + printf("\tSrc:\t%u\n", p->src); + printf("\tDst:\t%u\n", p->dst); + printf("\tLQI:\t%u\n", p->lqi); + printf("\tRSSI:\t%u\n", p->rssi); + + for (i = 0; i < p->length; i++) { + printf("%02X ", p->data[i]); + } + send(p->src, p->length, p->data); + p->processing--; + printf("\n"); + } + else if (m.type == ENOBUFFER) { + puts("Transceiver buffer full"); + } + else { + puts("Unknown packet received"); + } + } +} + +int main(void) { + int radio_pid; + uint8_t i; + for (i = 0; i < SND_BUFFER_SIZE; i++) { + memset(snd_buffer[i], i, CC1100_MAX_DATA_LENGTH); + } + thread_create(shell_stack_buffer, SHELL_STACK_SIZE, PRIORITY_MAIN-2, CREATE_STACKTEST, shell_runner, "shell"); + radio_pid = thread_create(radio_stack_buffer, RADIO_STACK_SIZE, PRIORITY_MAIN-2, CREATE_STACKTEST, radio, "radio"); + transceiver_init(TRANSCEIVER_CC1100); + transceiver_start(); + transceiver_register(TRANSCEIVER_CC1100, radio_pid); + sender(NULL); + + printf("Config:\n"); + printf("\tid: %u\n", sysconfig.id); + printf("\taddr: %u\n", sysconfig.radio_address); + printf("\tchannel: %u\n", sysconfig.radio_channel); + + while (1) { + extern void thread_print_all(void); + thread_print_all(); + print_buffer(NULL); + swtimer_usleep(10000000); + } +} diff --git a/projects/msb430_cc110x_ng/tests/hello-world b/projects/msb430_cc110x_ng/tests/hello-world new file mode 100755 index 000000000..acde8265f --- /dev/null +++ b/projects/msb430_cc110x_ng/tests/hello-world @@ -0,0 +1,13 @@ +#!/usr/bin/expect + +set timeout 5 + +spawn pseudoterm $env(PORT) + +expect { + "Hello World!" {} + timeout { exit 1 } +} + +puts "\nTest successful!\n" + diff --git a/projects/pingpong/Jamfile b/projects/pingpong/Jamfile index e2ed342b5..2de8f8253 100644 --- a/projects/pingpong/Jamfile +++ b/projects/pingpong/Jamfile @@ -1,6 +1,4 @@ SubDir TOP projects pingpong ; -# LOCATE_TARGET = $(SEARCH_SOURCE)/bin ; -Library pingpong : main.c ; - -LinkLibraries $(BOARD).elf : pingpong ; +Module pingpong : main.c ; +UseModule pingpong ; diff --git a/projects/pingpong/main.c b/projects/pingpong/main.c index daf898b88..0a4a910a9 100644 --- a/projects/pingpong/main.c +++ b/projects/pingpong/main.c @@ -5,7 +5,7 @@ void second_thread(void) { printf("second_thread starting.\n"); - msg m; + msg_t m; while(1) { msg_receive(&m); @@ -15,13 +15,15 @@ void second_thread(void) { } } +char second_thread_stack[KERNEL_CONF_STACKSIZE_MAIN]; + int main(void) { printf("Hello world!\n"); - msg m; + msg_t m; - int pid = thread_create(KERNEL_CONF_STACKSIZE_MAIN, PRIORITY_MAIN-1, CREATE_WOUT_YIELD | CREATE_STACKTEST, second_thread, "pong"); + int pid = thread_create(second_thread_stack, sizeof(second_thread_stack), PRIORITY_MAIN-1, CREATE_WOUT_YIELD | CREATE_STACKTEST, second_thread, "pong"); m.content.value = 1; diff --git a/projects/pingpong_sync/main.c b/projects/pingpong_sync/main.c index 739ec3acf..47989a267 100644 --- a/projects/pingpong_sync/main.c +++ b/projects/pingpong_sync/main.c @@ -5,7 +5,7 @@ void second_thread(void) { printf("second_thread starting.\n"); - msg m; + msg_t m; int i = 1; while(1) { msg_receive(&m); @@ -15,13 +15,15 @@ void second_thread(void) { } } +char second_thread_stack[8192]; + int main(void) { printf("Hello world!\n"); - msg m; + msg_t m; - int pid = thread_create(8192, PRIORITY_MAIN-1, CREATE_WOUT_YIELD | CREATE_STACKTEST, second_thread, "pong"); + int pid = thread_create(second_thread_stack, sizeof(second_thread_stack), PRIORITY_MAIN-1, CREATE_WOUT_YIELD | CREATE_STACKTEST, second_thread, "pong"); m.content.value = 1; diff --git a/projects/skel/tests/hello-world b/projects/skel/tests/hello-world index 6f4a6ca81..acde8265f 100755 --- a/projects/skel/tests/hello-world +++ b/projects/skel/tests/hello-world @@ -2,7 +2,7 @@ set timeout 5 -spawn board/msba2/tools/bin/pseudoterm $env(PORT) +spawn pseudoterm $env(PORT) expect { "Hello World!" {} diff --git a/projects/test_cc110x_ng/Jamfile b/projects/test_cc110x_ng/Jamfile new file mode 100644 index 000000000..5ef69ea23 --- /dev/null +++ b/projects/test_cc110x_ng/Jamfile @@ -0,0 +1,5 @@ +SubDir TOP projects test_cc110x_ng ; + +Module test_cc110x_ng : main.c : cc110x_ng shell shell_commands transceiver ps rtc posix_io uart0 auto_init swtimer config ltc4150 ; + +UseModule test_cc110x_ng ; diff --git a/projects/test_cc110x_ng/main.c b/projects/test_cc110x_ng/main.c new file mode 100644 index 000000000..1470e4fde --- /dev/null +++ b/projects/test_cc110x_ng/main.c @@ -0,0 +1,172 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SHELL_STACK_SIZE (2048) +#define RADIO_STACK_SIZE (2048) + +#define SND_BUFFER_SIZE (100) +#define RCV_BUFFER_SIZE (64) + +#define SENDING_DELAY (5 * 1000) + +char shell_stack_buffer[SHELL_STACK_SIZE]; +char radio_stack_buffer[RADIO_STACK_SIZE]; + +uint8_t snd_buffer[SND_BUFFER_SIZE][CC1100_MAX_DATA_LENGTH]; + +msg_t msg_q[RCV_BUFFER_SIZE]; + +static msg_t mesg; +static transceiver_command_t tcmd; +static radio_packet_t p; + +static uint32_t sending_delay = SENDING_DELAY; + +void sender(char *count); +void print_buffer(char *unused); +void switch2rx(char *unused); +void powerdown(char *unused); +void set_delay(char *delay); + +shell_t shell; +const shell_command_t sc[] = { + {"on", "", switch2rx}, + {"off", "", powerdown}, + {"snd", "", sender}, + {"delay", "", set_delay}, + {"buffer", "", print_buffer}, + {NULL, NULL, NULL}}; + +void shell_runner(void) { + shell_init(&shell, sc, uart0_readc, uart0_putc); + posix_open(uart0_handler_pid, 0); + shell_run(&shell); +} + +void sender(char *count) { + unsigned int c, i; + + mesg.type = SND_PKT; + mesg.content.ptr = (char*) &tcmd; + + tcmd.transceivers = TRANSCEIVER_CC1100; + tcmd.data = &p; + + p.length = CC1100_MAX_DATA_LENGTH; + p.dst = 0; + + sscanf(count, "snd %u", &c); + for (i = 0; i < c; i++) { + puts("."); + p.data = snd_buffer[i % SND_BUFFER_SIZE]; + msg_send(&mesg, transceiver_pid, 1); + swtimer_usleep(sending_delay); + } +} + +void print_buffer(char *unused) { + uint8_t i; + extern radio_packet_t transceiver_buffer[]; + for (i = 0; i < TRANSCEIVER_BUFFER_SIZE; i++) { + printf("[%u] %u # %u # %u\n", i, transceiver_buffer[i].processing, transceiver_buffer[i].length, transceiver_buffer[i].data[i]); + } + extern rx_buffer_t cc110x_rx_buffer[]; + for (i = 0; i < TRANSCEIVER_BUFFER_SIZE; i++) { + printf("[%u] %u # %u \n", i, cc110x_rx_buffer[i].packet.length, cc110x_rx_buffer[i].packet.data[i]); + } +} + +void switch2rx(char *unused) { + mesg.type = SWITCH_RX; + mesg.content.ptr = (char*) &tcmd; + + tcmd.transceivers = TRANSCEIVER_CC1100; + puts("Turning transceiver on"); + if (msg_send(&mesg, transceiver_pid, 1)) { + puts("\tsuccess"); + } +} + +void powerdown(char *unused) { + mesg.type = POWERDOWN; + mesg.content.ptr = (char*) &tcmd; + + tcmd.transceivers = TRANSCEIVER_CC1100; + puts("Turning transceiver off"); + if (msg_send(&mesg, transceiver_pid, 1)) { + puts("\tsuccess"); + } +} + +void set_delay(char *delay) { + uint32_t d; + + if (sscanf(delay, "delay %lu", &d) == 1) { + sending_delay = d; + } + else { + puts("Usage:\tdelay <µs>"); + } +} + +void radio(void) { + msg_t m; + radio_packet_t *p; + uint8_t i; + + msg_init_queue(msg_q, RCV_BUFFER_SIZE); + + while (1) { + msg_receive(&m); + if (m.type == PKT_PENDING) { + p = (radio_packet_t*) m.content.ptr; + printf("Packet waiting, process %p...\n", p); + printf("\tLength:\t%u\n", p->length); + printf("\tSrc:\t%u\n", p->src); + printf("\tDst:\t%u\n", p->dst); + printf("\tLQI:\t%u\n", p->lqi); + printf("\tRSSI:\t%u\n", p->rssi); + + for (i = 0; i < p->length; i++) { + printf("%02X ", p->data[i]); + } + p->processing--; + printf("\n"); + } + else if (m.type == ENOBUFFER) { + puts("Transceiver buffer full"); + } + else { + puts("Unknown packet received"); + } + } +} + +int main(void) { + int radio_pid; + uint8_t i; + for (i = 0; i < SND_BUFFER_SIZE; i++) { + memset(snd_buffer[i], i, CC1100_MAX_DATA_LENGTH); + } + thread_create(shell_stack_buffer, SHELL_STACK_SIZE, PRIORITY_MAIN-1, CREATE_STACKTEST, shell_runner, "shell"); + radio_pid = thread_create(radio_stack_buffer, RADIO_STACK_SIZE, PRIORITY_MAIN-2, CREATE_STACKTEST, radio, "radio"); + transceiver_init(TRANSCEIVER_CC1100); + transceiver_start(); + transceiver_register(TRANSCEIVER_CC1100, radio_pid); + + while (1) { +// LED_GREEN_TOGGLE; + hwtimer_wait(1000 * 1000); + } +} diff --git a/projects/test_cc110x_ng/tests/hello-world b/projects/test_cc110x_ng/tests/hello-world new file mode 100755 index 000000000..acde8265f --- /dev/null +++ b/projects/test_cc110x_ng/tests/hello-world @@ -0,0 +1,13 @@ +#!/usr/bin/expect + +set timeout 5 + +spawn pseudoterm $env(PORT) + +expect { + "Hello World!" {} + timeout { exit 1 } +} + +puts "\nTest successful!\n" + diff --git a/projects/test_hwtimer_basic/Jamfile b/projects/test_hwtimer_basic/Jamfile new file mode 100644 index 000000000..e9f9af9ec --- /dev/null +++ b/projects/test_hwtimer_basic/Jamfile @@ -0,0 +1,5 @@ +SubDir TOP projects test_hwtimer ; + +Module test_hwtimer : main.c : hwtimer ; + +UseModule test_hwtimer ; diff --git a/projects/test_hwtimer_basic/main.c b/projects/test_hwtimer_basic/main.c new file mode 100644 index 000000000..8e215d105 --- /dev/null +++ b/projects/test_hwtimer_basic/main.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include + +void callback(void* ptr) { + puts((char*)ptr); +} + +extern uint32_t hwtimer_now(); + +int main(void) +{ + puts("hwtimer test project."); + + puts("Initializing hwtimer..."); + hwtimer_init(); + + puts("Initializing hwtimer [OK]."); + + +// while (TA0R < 20000); + + hwtimer_set(20000LU, callback, (void*)"callback1"); + hwtimer_set(50000LU, callback, (void*)"callback2"); + hwtimer_set(30000LU, callback, (void*)"callback3"); + + puts("hwtimer set."); +} diff --git a/projects/test_hwtimer_basic/tests/test_hwtimer.py b/projects/test_hwtimer_basic/tests/test_hwtimer.py new file mode 100755 index 000000000..261c511bb --- /dev/null +++ b/projects/test_hwtimer_basic/tests/test_hwtimer.py @@ -0,0 +1,17 @@ +#!/usr/bin/python + +import pexpect +import os +import subprocess + +child = pexpect.spawn ("board/msba2/tools/bin/pseudoterm %s" % os.environ["PORT"]) + +null = open('/dev/null', 'wb') +subprocess.call(['jam', 'reset'], stdout=null) + +child.expect ('OK\r\n'); +child.expect ('callback1\r\n'); +child.expect ('callback3\r\n'); +child.expect ('callback2\r\n'); +print("Test successful!") + diff --git a/projects/test_shell/test_shell.c b/projects/test_shell/test_shell.c index 7499c9b85..6839969af 100644 --- a/projects/test_shell/test_shell.c +++ b/projects/test_shell/test_shell.c @@ -29,9 +29,9 @@ void shell_putchar(int c) { } const shell_command_t shell_commands[] = { - {"start_test", print_teststart}, - {"end_test", print_testend}, - {NULL, NULL} + {"start_test", "", print_teststart}, + {"end_test", "", print_testend}, + {NULL, NULL, NULL} }; int main(void) { @@ -43,10 +43,8 @@ int main(void) { posix_open(uart0_handler_pid, 0); shell_t shell; - shell_init(&shell, shell_readc, shell_putchar); + shell_init(&shell, shell_commands, shell_readc, shell_putchar); - shell.command_list = shell_commands; - shell_run(&shell); return 0; diff --git a/projects/test_sleep/Jamfile b/projects/test_sleep/Jamfile index eee5c1fa2..83289e1e2 100644 --- a/projects/test_sleep/Jamfile +++ b/projects/test_sleep/Jamfile @@ -1,5 +1,5 @@ SubDir TOP projects test_sleep ; -Module test_sleep : main.c : hwtimer ; +Module test_sleep : main.c : hwtimer ps ; UseModule test_sleep ; diff --git a/projects/test_sleep/main.c b/projects/test_sleep/main.c index 32e05f90b..59e9e0013 100644 --- a/projects/test_sleep/main.c +++ b/projects/test_sleep/main.c @@ -2,6 +2,7 @@ #include #include #include +#include int integer = 0; int i = 0; @@ -11,21 +12,20 @@ void second_thread(void) { while(1) { integer++; printf("sleeper: running. integer=%i, i=%i.\n", integer, i); - if (integer % 100 == 0) { + if (integer % 1 == 0) { printf("Going to sleep.\n"); thread_sleep(); } } } +char second_thread_stack[KERNEL_CONF_STACKSIZE_DEFAULT*2]; int main(void) { hwtimer_init(); - printf("Hello world!\n"); - - int pid = thread_create(KERNEL_CONF_STACKSIZE_DEFAULT, PRIORITY_MAIN-1, CREATE_STACKTEST | CREATE_SLEEPING | CREATE_WOUT_YIELD, second_thread, "sleeper"); + int pid = thread_create(second_thread_stack, sizeof(second_thread_stack), PRIORITY_MAIN-1, CREATE_STACKTEST | CREATE_SLEEPING | CREATE_WOUT_YIELD, second_thread, "sleeper"); if (pid < 0) { puts("Error creating second_thread! Stopping test."); @@ -35,10 +35,12 @@ int main(void) while(1) { i++; printf(" main: running. integer=%i, i=%i.\n", integer, i); - if (i % 100 == 0) { + if (i % 1 == 0) { + thread_print_all(); printf("Waking up sleeper.\n"); thread_wakeup(pid); - fk_yield(); + thread_print_all(); + thread_yield(); } } } diff --git a/projects/test_suite/Jamfile b/projects/test_suite/Jamfile new file mode 100644 index 000000000..dfb96deb7 --- /dev/null +++ b/projects/test_suite/Jamfile @@ -0,0 +1,12 @@ +# +# Copyright (C) 2008, 2009, 2010 FU Berlin +# +# Author: Kaspar Schleiser +# + +SubDir TOP projects test_suite ; + +Module test_suite : test_suite.c mutex_trylock_fail.c thread_sleep.c + : shell posix_io ps uart0 hwtimer ; + +UseModule test_suite ; diff --git a/projects/test_suite/mutex_trylock_fail.c b/projects/test_suite/mutex_trylock_fail.c new file mode 100644 index 000000000..079d0d960 --- /dev/null +++ b/projects/test_suite/mutex_trylock_fail.c @@ -0,0 +1,30 @@ +#include +#include + +#include +#include +#include + +mutex_t mutex; + +static void second_thread(void) { + puts(" 2nd: trying to lock mutex..."); + mutex_trylock(&mutex); + puts(" 2nd: done."); +} + +static char second_stack[KERNEL_CONF_STACKSIZE_MAIN]; + +void mutex_trylock_fail(char* cmdline) +{ + puts("main: locking mutex..."); + mutex_lock(&mutex); + + puts("main: creating thread..."); + thread_create(second_stack, KERNEL_CONF_STACKSIZE_MAIN, PRIORITY_MAIN-1, CREATE_STACKTEST, second_thread, "nr2"); + + puts("main: thread created. Unlocking mutex..."); + mutex_unlock(&mutex, true); + + puts("main: mutex unlocked."); +} diff --git a/projects/test_suite/test_suite.c b/projects/test_suite/test_suite.c new file mode 100644 index 000000000..40a019fc0 --- /dev/null +++ b/projects/test_suite/test_suite.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2008, 2009, 2010 Kaspar Schleiser + */ + +#include +#include +#include + +#include +#include +#include + +void print_teststart(char* str) { + printf("[TEST_START]\n"); +} + +void print_testend(char* str) { + printf("[TEST_END]\n"); +} + +int shell_readc() { + char c = 0; + posix_read(uart0_handler_pid, &c, 1); + return c; +} + +void shell_putchar(int c) { + putchar(c); +} + +void mutex_trylock_fail(char* cmdline); +void test_thread_sleep(char* line); + +const shell_command_t shell_commands[] = { + {"start_test", "", print_teststart}, + {"end_test", "", print_testend}, + {"mutex_trylock_fail", "", mutex_trylock_fail}, + {"thread_sleep", "", test_thread_sleep}, + {NULL, NULL, NULL} +}; + +int main(void) { + //printf("Moin. build on %s %s SVN-Revision: %s\n", kernel_builddate, kernel_buildtime, kernel_svnrevision); + printf("test_shell.\n"); + + board_uart0_init(); + + posix_open(uart0_handler_pid, 0); + + shell_t shell; + shell_init(&shell, shell_commands, shell_readc, shell_putchar); + + shell_run(&shell); + + return 0; +} + + diff --git a/projects/test_suite/tests/01-basic b/projects/test_suite/tests/01-basic new file mode 100755 index 000000000..bdeb11773 --- /dev/null +++ b/projects/test_suite/tests/01-basic @@ -0,0 +1,30 @@ +#!/usr/bin/expect + +set timeout 5 + +spawn pseudoterm $env(PORT) + +expect { + ">$" {} + timeout { exit 1 } +} + +send "start_test\n" +expect { + "\[TEST_START\]" {} + timeout { exit 1 } +} + +expect { + ">$" {} + timeout { exit 1 } +} + +send "end_test\n" + +expect { + "\[TEST_END\]" {} + timeout { exit 1 } +} + +puts "\nTest successful!\n" diff --git a/projects/test_suite/tests/02-inputlength-regression b/projects/test_suite/tests/02-inputlength-regression new file mode 100755 index 000000000..ae130f551 --- /dev/null +++ b/projects/test_suite/tests/02-inputlength-regression @@ -0,0 +1,81 @@ +#!/usr/bin/expect + +set timeout 1 + +spawn pseudoterm $env(PORT) + +sleep 1 + +expect { + ">$" {} + timeout { exit 1 } +} + +send "123456789012345678901234567890123456789012345678901234567890\n" +expect { + "shell: command not found." {} + timeout { exit 1 } +} + +send "123456789012345678901234567890123456789012345678901234567890\n" +expect { + "shell: command not found." {} + timeout { exit 1 } +} + +send "123456789012345678901234567890123456789012345678901234567890\n" +expect { + "shell: command not found." {} + timeout { exit 1 } +} + +send "123456789012345678901234567890123456789012345678901234567890\n" +expect { + "shell: command not found." {} + timeout { exit 1 } +} + +send "123456789012345678901234567890123456789012345678901234567890\n" +expect { + "shell: command not found." {} + timeout { exit 1 } +} + +send "123456789012345678901234567890123456789012345678901234567890\n" +expect { + "shell: command not found." {} + timeout { exit 1 } +} + +send "123456789012345678901234567890123456789012345678901234567890\n" +expect { + "shell: command not found." {} + timeout { exit 1 } +} + +send "123456789012345678901234567890123456789012345678901234567890\n" +expect { + "shell: command not found." {} + timeout { exit 1 } +} + + +send "start_test\n" +expect { + "\[TEST_START\]" {} + timeout { exit 1 } +} + +expect { + ">$" {} + timeout { exit 1 } +} + +send "end_test\n" + +expect { + "\[TEST_END\]" {} + timeout { exit 1 } +} + +puts "\nTest successful!\n" diff --git a/projects/test_suite/tests/02-unknown-command b/projects/test_suite/tests/02-unknown-command new file mode 100755 index 000000000..4dc625042 --- /dev/null +++ b/projects/test_suite/tests/02-unknown-command @@ -0,0 +1,20 @@ +#!/usr/bin/expect + +set timeout 2 + +spawn pseudoterm $env(PORT) + +sleep 1 + +expect { + ">$" {} + timeout { exit 1 } +} + +send "some_definately_unknown_command\n" +expect { + "shell: command "some_definately_unknown_command" not found." {} + timeout { exit 1 } +} + +puts "\nTest successful!\n" diff --git a/projects/test_suite/tests/03-mutex_trylock_fail b/projects/test_suite/tests/03-mutex_trylock_fail new file mode 100755 index 000000000..e9fa06827 --- /dev/null +++ b/projects/test_suite/tests/03-mutex_trylock_fail @@ -0,0 +1,56 @@ +#!/usr/bin/expect + +set timeout 5 + +spawn pseudoterm $env(PORT) + +expect { + ">$" {} + timeout { exit 1 } +} + +send "start_test\n" +expect { + "\[TEST_START\]" {} + timeout { exit 1 } +} + +expect { + ">$" {} + timeout { exit 1 } +} + +send "mutex_trylock_fail\n" +expect { + "main: locking mutex..." {} + timeout { exit 1 } +} +expect { + "main: creating thread..." {} + timeout { exit 1 } +} +expect { + "2nd: trying to lock mutex..." {} + timeout { exit 1 } +} +expect { + "2nd: done." {} + timeout { exit 1 } +} +expect { + "main: thread created. Unlocking mutex..." {} + timeout { exit 1 } +} +expect { + "main: mutex unlocked." {} + timeout { exit 1 } +} + +send "end_test\n" + +expect { + "\[TEST_END\]" {} + timeout { exit 1 } +} + +puts "\nTest successful!\n" diff --git a/projects/test_suite/tests/04-thread_sleep b/projects/test_suite/tests/04-thread_sleep new file mode 100755 index 000000000..1734706b7 --- /dev/null +++ b/projects/test_suite/tests/04-thread_sleep @@ -0,0 +1,70 @@ +#!/usr/bin/expect + +set timeout 5 + +spawn pseudoterm $env(PORT) + +expect { + ">$" {} + timeout { exit 1 } +} + +send "start_test\n" +expect { + "\[TEST_START\]" {} + timeout { exit 1 } +} + +expect { + ">$" {} + timeout { exit 1 } +} + +send "thread_sleep\n" +expect { +" main: running. integer=0, i=1." {} +" main: running. integer=0, i=2." {} +"Waking up sleeper." {} +"sleeper: running. integer=1, i=2." {} +"sleeper: running. integer=2, i=2." {} +"Going to sleep." {} +" main: running. integer=2, i=3." {} +" main: running. integer=2, i=4." {} +"Waking up sleeper." {} +"Woke up!" {} +"sleeper: running. integer=3, i=4." {} +"sleeper: running. integer=4, i=4." {} +"Going to sleep." {} +" main: running. integer=4, i=5." {} +" main: running. integer=4, i=6." {} +"Waking up sleeper." {} +"Woke up!" {} +"sleeper: running. integer=5, i=6." {} +"sleeper: running. integer=6, i=6." {} +"Going to sleep." {} +" main: running. integer=6, i=7." {} +" main: running. integer=6, i=8." {} +"Waking up sleeper." {} +"Woke up!" {} +"sleeper: running. integer=7, i=8." {} +"sleeper: running. integer=8, i=8." {} +"Going to sleep." {} +" main: running. integer=8, i=9." {} +" main: running. integer=8, i=10." {} +"Waking up sleeper." {} +"Woke up!" {} +"sleeper: running. integer=9, i=10." {} +"sleeper: running. integer=10, i=10." {} +"Going to sleep." {} + ">$" {} + timeout { exit 1 } +} + +send "end_test\n" + +expect { + "\[TEST_END\]" {} + timeout { exit 1 } +} + +puts "\nTest successful!\n" diff --git a/projects/test_suite/thread_sleep.c b/projects/test_suite/thread_sleep.c new file mode 100644 index 000000000..c88c01550 --- /dev/null +++ b/projects/test_suite/thread_sleep.c @@ -0,0 +1,39 @@ +#include +#include +#include + +static int integer = 0; +static int i = 0; + +static void second_thread(void) { + while(1) { + integer++; + printf("sleeper: running. integer=%i, i=%i.\n", integer, i); + if (integer % 2 == 0) { + printf("Going to sleep.\n"); + thread_sleep(); + printf("Woke up!\n"); + } + } +} + +static char second_thread_stack[KERNEL_CONF_STACKSIZE_DEFAULT*2]; + +void test_thread_sleep(char* line) +{ + int pid = thread_create(second_thread_stack, sizeof(second_thread_stack), PRIORITY_MAIN-1, CREATE_STACKTEST | CREATE_SLEEPING | CREATE_WOUT_YIELD, second_thread, "sleeper"); + + if (pid < 0) { + puts("Error creating second_thread! Stopping test."); + while(1); + } + + while(i < 10) { + i++; + printf(" main: running. integer=%i, i=%i.\n", integer, i); + if (i % 2 == 0) { + printf("Waking up sleeper.\n"); + thread_wakeup(pid); + } + } +} diff --git a/projects/test_swtimer_basic/Jamfile b/projects/test_swtimer_basic/Jamfile new file mode 100644 index 000000000..7a5e6acb0 --- /dev/null +++ b/projects/test_swtimer_basic/Jamfile @@ -0,0 +1,5 @@ +SubDir TOP projects expect_swtimer ; + +Module expect_swtimer : main.c : swtimer ; + +UseModule expect_swtimer ; diff --git a/projects/test_swtimer_basic/main.c b/projects/test_swtimer_basic/main.c new file mode 100644 index 000000000..0130aa4d6 --- /dev/null +++ b/projects/test_swtimer_basic/main.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include +#include + +void callback(void* ptr){ + puts((char*)ptr); +} + +void wakeup_thread(void){ + puts("wakeup"); +} + +void msg_thread(void){ + msg_t m; + msg_receive(&m); + printf("%s\n",(char*)m.content.ptr); +} + +int main(void) +{ + hwtimer_init(); + swtimer_init(); + + int pid1 = thread_create(8192, PRIORITY_MAIN-1, + CREATE_WOUT_YIELD | CREATE_SLEEPING | CREATE_STACKTEST, wakeup_thread, "nr1"); + + int pid2 = thread_create(8192, PRIORITY_MAIN-1, + /*CREATE_WOUT_YIELD | CREATE_SLEEPING |*/ CREATE_STACKTEST, msg_thread, "nr2"); + + + swtimer_t cbt; + swtimer_t wut; + swtimer_t mst; + /* test callback */ + swtimer_set_cb(&cbt,1000L,callback,"callback"); + /* test wake-up */ + swtimer_set_wakeup(&wut, 1000L, pid1); + /* test message */ + swtimer_set_msg(&mst,1000L, pid2, "message"); + + while(1); +} diff --git a/projects/test_swtimer_basic/tests/test_swtimer.py b/projects/test_swtimer_basic/tests/test_swtimer.py new file mode 100755 index 000000000..465e5562a --- /dev/null +++ b/projects/test_swtimer_basic/tests/test_swtimer.py @@ -0,0 +1,15 @@ +#!/usr/bin/python + +import pexpect +import os +import subprocess + +child = pexpect.spawn ("pseudoterm %s" % os.environ["PORT"]) + +null = open('/dev/null', 'wb') +subprocess.call(['jam', 'reset'], stdout=null) + +child.expect ('callback\r\n'); +child.expect ('wakeup\r\n'); +child.expect ('message\r\n'); +print("Test successful!") diff --git a/projects/test_swtimer_remove/main.c b/projects/test_swtimer_remove/main.c index 773265c75..414e57d61 100644 --- a/projects/test_swtimer_remove/main.c +++ b/projects/test_swtimer_remove/main.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include int main(void) { @@ -13,7 +13,7 @@ int main(void) swtimer_t t; puts("Setting timer...\n"); - swtimer_set_wakeup(&t, 10000000L, fk_thread->pid); + swtimer_set_wakeup(&t, 10000000L, active_thread->pid); puts("Small delay...\n"); hwtimer_wait(200000); puts("Removing timer...\n"); @@ -22,9 +22,9 @@ int main(void) swtimer_t t2; puts("Setting timer...\n"); - swtimer_set_wakeup(&t, 10000000L, fk_thread->pid); + swtimer_set_wakeup(&t, 10000000L, active_thread->pid); puts("Setting timer 2...\n"); - swtimer_set_wakeup(&t2, 50000000L, fk_thread->pid); + swtimer_set_wakeup(&t2, 50000000L, active_thread->pid); puts("Small delay...\n"); hwtimer_wait(200000); puts("Removing timer 1...\n"); @@ -34,9 +34,9 @@ int main(void) puts("Done.\n"); puts("Setting timer...\n"); - swtimer_set_wakeup(&t, 10000000L, fk_thread->pid); + swtimer_set_wakeup(&t, 10000000L, active_thread->pid); puts("Setting timer 2...\n"); - swtimer_set_wakeup(&t2, 50000000L, fk_thread->pid); + swtimer_set_wakeup(&t2, 50000000L, active_thread->pid); puts("Small delay...\n"); hwtimer_wait(200000); puts("Removing timer 2...\n"); diff --git a/projects/test_thread_basic/Jamfile b/projects/test_thread_basic/Jamfile new file mode 100644 index 000000000..3f9c7e01d --- /dev/null +++ b/projects/test_thread_basic/Jamfile @@ -0,0 +1,5 @@ +SubDir TOP projects test_thread_exit ; + +Module test_thread_exit : main.c ; + +UseModule test_thread_exit ; diff --git a/projects/test_thread_basic/main.c b/projects/test_thread_basic/main.c new file mode 100644 index 000000000..ff9584556 --- /dev/null +++ b/projects/test_thread_basic/main.c @@ -0,0 +1,14 @@ +#include +#include +#include +#include + +void second_thread(void) { + puts("second thread\n"); +} + +int main(void) +{ + int pid = thread_create(8192, PRIORITY_MAIN-1, CREATE_WOUT_YIELD | CREATE_STACKTEST, second_thread, "nr2"); + puts("first thread\n"); +} diff --git a/projects/test_thread_basic/tests/test_thread.py b/projects/test_thread_basic/tests/test_thread.py new file mode 100755 index 000000000..40df9e651 --- /dev/null +++ b/projects/test_thread_basic/tests/test_thread.py @@ -0,0 +1,15 @@ +#!/usr/bin/python + +import pexpect +import os +import subprocess + +child = pexpect.spawn("board/msba2/tools/bin/pseudoterm %s" % os.environ["PORT"]) + +null = open('/dev/null', 'wb') +subprocess.call(['jam', 'reset'], stdout=null) + +child.expect ('first thread\r\n') +child.expect ('second thread\r\n') +print("Test successful!") + diff --git a/projects/test_thread_exit/main.c b/projects/test_thread_exit/main.c index 3f09c7284..363d437a2 100644 --- a/projects/test_thread_exit/main.c +++ b/projects/test_thread_exit/main.c @@ -9,8 +9,10 @@ void second_thread(void) { puts("2nd: running..."); } +char second_thread_stack[8192]; + int main(void) { - int pid = thread_create(8192, PRIORITY_MAIN-1, CREATE_WOUT_YIELD | CREATE_STACKTEST, second_thread, "nr2"); + int pid = thread_create(second_thread_stack, sizeof(second_thread_stack), PRIORITY_MAIN-1, CREATE_WOUT_YIELD | CREATE_STACKTEST, second_thread, "nr2"); puts("Main thread exiting..."); } diff --git a/projects/watch/Jamfile b/projects/watch/Jamfile new file mode 100644 index 000000000..d3484567e --- /dev/null +++ b/projects/watch/Jamfile @@ -0,0 +1,5 @@ +SubDir TOP projects watch ; + +Module watch : main.c clock_app.c alarm_app.c : uart0 posix_io rtc display_putchar gpioint hwtimer board_buzzer auto_init ; + +UseModule watch ; diff --git a/projects/watch/alarm_app.c b/projects/watch/alarm_app.c new file mode 100644 index 000000000..92158382d --- /dev/null +++ b/projects/watch/alarm_app.c @@ -0,0 +1,62 @@ +#include +#include + +#include +#include +#include +#include + +#include "alarm_app.h" +#include "clock_app.h" +#include "watch.h" + +static char alarm_stack[KERNEL_CONF_STACKSIZE_DEFAULT]; + +static void alarm_thread(void) { + msg_t m; + + struct tm time; + + time.tm_sec = 1; + time.tm_min = 2; + time.tm_hour = 3; + + int active = 0; + + while(1) { + msg_receive(&m); + switch (m.type) { + case MSG_ACTIVATE: + { + time_print(&time); + if (active) { + } else { + } + break; + } + case MSG_DEACTIVATE: + { + break; + } + case MSG_BUTTON_HASH: + { + if (active) { + active = 0; + display_symbol(LCD_ICON_ALARM, SEG_OFF); + } else { + active = 1; + display_symbol(LCD_ICON_ALARM, SEG_ON); + } + break; + } + default: + { + printf("def alarm\n"); + } + } + } +} + +int alarm_app_init() { + return thread_create(alarm_stack, sizeof(alarm_stack), PRIORITY_MAIN-1, CREATE_STACKTEST, alarm_thread, "alarm"); +} diff --git a/projects/watch/alarm_app.h b/projects/watch/alarm_app.h new file mode 100644 index 000000000..569be69b0 --- /dev/null +++ b/projects/watch/alarm_app.h @@ -0,0 +1,6 @@ +#ifndef __ALARM_APP_H +#define __ALARM_APP_H + +int alarm_app_init(); + +#endif /* __ALARM_APP_H */ diff --git a/projects/watch/clock_app.c b/projects/watch/clock_app.c new file mode 100644 index 000000000..f46fc35bd --- /dev/null +++ b/projects/watch/clock_app.c @@ -0,0 +1,58 @@ +#include +#include + +#include +#include +#include + +#include "clock_app.h" +#include "watch.h" + +void time_print(struct tm *time) { + printf("%02i %02i%02i\n", time->tm_sec, time->tm_hour, time->tm_min); +} + +static char clock_stack[KERNEL_CONF_STACKSIZE_DEFAULT]; + +static void clock_thread(void) { + msg_t m; + + int active = 0; + rtc_second_pid = thread_getpid(); + + while(1) { + msg_receive(&m); + switch (m.type) { + case RTC_SECOND: + { + if (! active) break; + } + case MSG_ACTIVATE: + { + active = 1; + struct tm now; + rtc_get_localtime(&now); + time_print(&now); + break; + } + case MSG_DEACTIVATE: + { + active = 0; + break; + } + case MSG_BUTTON_HASH: + { + printf("hashclock\n"); + break; + } + default: + { + printf("def clock\n"); + } + } + } +} + +int clock_app_init() { + return thread_create(clock_stack, sizeof(clock_stack), PRIORITY_MAIN-1, CREATE_STACKTEST, clock_thread, "clock"); +} diff --git a/projects/watch/clock_app.h b/projects/watch/clock_app.h new file mode 100644 index 000000000..084f58866 --- /dev/null +++ b/projects/watch/clock_app.h @@ -0,0 +1,7 @@ +#ifndef __CLOCK_APP_H +#define __CLOCK_APP_H + +int clock_app_init(); +void time_print(struct tm *time); + +#endif /* __CLOCK_APP_H */ diff --git a/projects/watch/main.c b/projects/watch/main.c new file mode 100644 index 000000000..94bbcc864 --- /dev/null +++ b/projects/watch/main.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "watch.h" +#include "alarm_app.h" +#include "clock_app.h" + +#define NUM_APPS 2 +int napps = NUM_APPS; +int apps[NUM_APPS]; + +int button_thread = 0; +void button_star(void) { + msg_t m; + + if (button_thread) { + m.type = MSG_BUTTON_STAR; + msg_send(&m, button_thread, false); + } +} + +int main(void) +{ + memset(apps, '\0', sizeof(apps)); + apps[0] = clock_app_init(); + apps[1] = alarm_app_init(); + + gpioint_set(2, BUTTON_STAR_PIN, (GPIOINT_RISING_EDGE | GPIOINT_DEBOUNCE), button_star); + button_thread = thread_getpid(); + + int active_app = 0; + + msg_t m; + + //buzzer_beep(15, 5000); + + printf("ukleos\n"); + + m.type = MSG_ACTIVATE; + msg_send(&m, apps[active_app], true); + + while(1) { + msg_receive(&m); + + switch (m.type) { + case MSG_BUTTON_STAR: { + m.type = MSG_DEACTIVATE; + msg_send(&m, apps[active_app], true); + + active_app++; + + if (active_app == (NUM_APPS)) active_app = 0; + + m.type = MSG_ACTIVATE; + msg_send(&m, apps[active_app], true); + + // buzzer_beep(15, 5000); + + break; + } + case MSG_BUTTON_HASH: + { + m.type = MSG_BUTTON_HASH; + msg_send(&m, apps[active_app], true); + break; + } + default: + { + printf("msg\n"); + } + } + } +} diff --git a/projects/watch/tests/hello-world b/projects/watch/tests/hello-world new file mode 100755 index 000000000..acde8265f --- /dev/null +++ b/projects/watch/tests/hello-world @@ -0,0 +1,13 @@ +#!/usr/bin/expect + +set timeout 5 + +spawn pseudoterm $env(PORT) + +expect { + "Hello World!" {} + timeout { exit 1 } +} + +puts "\nTest successful!\n" + diff --git a/projects/watch/watch.h b/projects/watch/watch.h new file mode 100644 index 000000000..c2cd7ddbe --- /dev/null +++ b/projects/watch/watch.h @@ -0,0 +1,9 @@ +#ifndef __WATCH_H +#define __WATCH_H + +#define MSG_ACTIVATE 0 +#define MSG_DEACTIVATE 1 +#define MSG_BUTTON_STAR 2 +#define MSG_BUTTON_HASH 3 + +#endif /* __WATCH_H */ diff --git a/projects/wiselib/Jamfile b/projects/wiselib/Jamfile new file mode 100644 index 000000000..3301526cb --- /dev/null +++ b/projects/wiselib/Jamfile @@ -0,0 +1,5 @@ +SubDir TOP projects wiselib ; + +Module wiseleb : main.c : cc110x_ng shell shell_commands transceiver ps rtc posix_io uart0 auto_init swtimer config ltc4150 ; + +UseModule wiseleb ; diff --git a/projects/wiselib/main.c b/projects/wiselib/main.c new file mode 100644 index 000000000..ecf6cba1d --- /dev/null +++ b/projects/wiselib/main.c @@ -0,0 +1,42 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SHELL_STACK_SIZE (2048) +#define RADIO_STACK_SIZE (2048) + +#define SND_BUFFER_SIZE (100) +#define RCV_BUFFER_SIZE (64) + +#define SENDING_DELAY (5 * 1000) + +char shell_stack_buffer[SHELL_STACK_SIZE]; +char radio_stack_buffer[RADIO_STACK_SIZE]; + +uint8_t snd_buffer[SND_BUFFER_SIZE][CC1100_MAX_DATA_LENGTH]; + +msg_t msg_q[RCV_BUFFER_SIZE]; + +static msg_t mesg; +static transceiver_command_t tcmd; +static radio_packet_t p; + +static uint32_t sending_delay = SENDING_DELAY; + +void sender(char *count); +void print_buffer(char *unused); +void switch2rx(char *unused); +void powerdown(char *unused); +void set_delay(char *delay); + +int main(void){} diff --git a/projects/wiselib/script b/projects/wiselib/script new file mode 100755 index 000000000..c5978378c --- /dev/null +++ b/projects/wiselib/script @@ -0,0 +1,3 @@ +echo "Doing stuff..." +cd $FEUERWHERE_PATH +jam -sPROJECT=wiselib diff --git a/sys/Jamfile b/sys/Jamfile index 0ae65f81c..6de621983 100644 --- a/sys/Jamfile +++ b/sys/Jamfile @@ -27,14 +27,19 @@ SubDir TOP sys ; +Module timex : timex.c ; +Module vtimer : vtimer.c : hwtimer timex ; Module swtimer : swtimer.c : hwtimer ; Module posix_io : posix_io.c ; +Module config : config.c : board_config ; Module auto_init : auto_init.c ; Module chardev_thread : chardev_thread.c : ringbuffer ; Module uart0 : uart0.c : ringbuffer chardev_thread ; +Module transceiver : transceiver.c ; + SubInclude TOP sys net ; SubInclude TOP sys lib ; SubInclude TOP sys shell ; diff --git a/sys/auto_init.c b/sys/auto_init.c index bf98ae755..d06674cd1 100644 --- a/sys/auto_init.c +++ b/sys/auto_init.c @@ -1,6 +1,8 @@ #include #include -#include +#include "board_uart0.h" +#include "rtc.h" +#include "diskio.h" #include #include @@ -10,6 +12,16 @@ extern void main(void); void auto_init(void) { +#ifdef MODULE_BOARD_DISPLAY + extern void lcd_init(); + lcd_init(); + DEBUG("DISP OK"); +#endif +#ifdef MODULE_DISPLAY_PUTCHAR + extern void init_display_putchar(); + init_display_putchar(); + DEBUG("DISP OK"); +#endif #ifdef MODULE_HWTIMER DEBUG("Auto init hwtimer module.\n"); hwtimer_init(); @@ -42,6 +54,14 @@ void auto_init(void) { #ifdef MODULE_LTC4150 DEBUG("Auto init ltc4150 module.\n"); ltc4150_init(); +#endif +#ifdef MODULE_MCI + DEBUG("Auto init mci module.\n"); + MCI_initialize(); +#endif +#ifdef MODULE_PROFILING + extern void profiling_init(void); + profiling_init(); #endif main(); } diff --git a/sys/chardev_thread.c b/sys/chardev_thread.c index 6c90928c4..d30782926 100644 --- a/sys/chardev_thread.c +++ b/sys/chardev_thread.c @@ -16,13 +16,13 @@ static int min(int a, int b) { else return b; } -void chardev_loop(ringbuffer *rb) { - msg m; +void chardev_loop(ringbuffer_t *rb) { + msg_t m; int pid = thread_getpid(); int reader_pid = -1; - struct posix_iop *r = NULL; + struct posix_iop_t *r = NULL; puts("UART0 thread started."); @@ -46,7 +46,7 @@ void chardev_loop(ringbuffer *rb) { m.content.value = -EINVAL; msg_reply(&m, &m); } else { - r = (struct posix_iop *)m.content.ptr; + r = (struct posix_iop_t *)m.content.ptr; } break; case CLOSE: diff --git a/sys/config.c b/sys/config.c new file mode 100644 index 000000000..d63e14e5e --- /dev/null +++ b/sys/config.c @@ -0,0 +1,7 @@ +#include + +config_t sysconfig = { + 0, ///< default ID + 0, ///< default radio address + 0, ///< default radio channel +}; diff --git a/sys/include/board_uart0.h b/sys/include/board_uart0.h index 2819ef61b..d38c22c75 100644 --- a/sys/include/board_uart0.h +++ b/sys/include/board_uart0.h @@ -3,8 +3,11 @@ extern int uart0_handler_pid; -void board_uart0_init(); +void board_uart0_init(void); void uart0_handle_incoming(int c); -void uart0_notify_thread(); +void uart0_notify_thread(void); + +int uart0_readc(void); +void uart0_putc(int c); #endif /* __BOARD_UART0_H */ diff --git a/sys/include/chardev_thread.h b/sys/include/chardev_thread.h index 4596cda83..bb811bddd 100644 --- a/sys/include/chardev_thread.h +++ b/sys/include/chardev_thread.h @@ -3,6 +3,6 @@ #include -void chardev_loop(ringbuffer *rb); +void chardev_loop(ringbuffer_t *rb); #endif /* __CHARDEV_THREAD_H */ diff --git a/sys/include/posix_io.h b/sys/include/posix_io.h index 656e1ea3e..b39bdb3a3 100644 --- a/sys/include/posix_io.h +++ b/sys/include/posix_io.h @@ -6,7 +6,7 @@ #define READ 2 #define WRITE 3 -struct posix_iop { +struct posix_iop_t { int nbytes; char *buffer; }; diff --git a/sys/include/radio/types.h b/sys/include/radio/types.h index 7018480f6..c84a12e09 100644 --- a/sys/include/radio/types.h +++ b/sys/include/radio/types.h @@ -40,6 +40,7 @@ and the mailinglist (subscription via web site) #include #include +#include typedef uint8_t protocol_t; ///< Packet protocol type typedef uint16_t radio_address_t; ///< Radio layer address type @@ -73,6 +74,22 @@ typedef struct __attribute__ ((packed)) packet_info_t bool promiscuous; ///< Radio layer: whether network interface is in promiscuous mode } packet_info_t; + +/** + * @brief General link layer packet format + */ +typedef struct __attribute__ ((packed)) { + uint8_t processing; ///< internal processing state + uint16_t src; ///< Radio source address + uint16_t dst; ///< Radio destination address + uint8_t rssi; ///< Radio Signal Strength Indication + uint8_t lqi; ///< Link Quality Indicator + timex_t toa; ///< Time of Arrival + uint8_t length; ///< Length of payload + uint8_t *data; ///< Payload +} radio_packet_t; + + /** * Packet handler (receive function) of all layers. * @param [in/out] payload Pointer to packet payload data diff --git a/sys/include/shell.h b/sys/include/shell.h index daa739b53..9020914c8 100644 --- a/sys/include/shell.h +++ b/sys/include/shell.h @@ -34,8 +34,9 @@ and the mailinglist (subscription via web site) //#include "hashtable.h" -typedef struct shell_commant_t { +typedef struct shell_command_t { char* name; + char* desc; void (*handler)(char*); } shell_command_t; @@ -47,16 +48,12 @@ typedef struct shell_t { /** * @brief Initialize a shell object + * @param shell Pointer to preallocated shell object + * @param shell_commands Pointer to shell command structure. See test_shell project for example. + * @param read_char Pointer to input device read function. Should return exactly one byte or block. + * @param put_char Pointer to output funtion. currently unused, shell code will use printf. */ -void shell_init(shell_t *shell, int(*read_char)(void), void (*put_char)(int)); - -/** - * @brief Register a new command handler for a shell. - * @param shell Shell object. - * @param name Name of the command to register. - * @param handler Function pointer to handler that takes the complete command line as parameter. - */ -//void shell_register_cmd(shell_t *shell, char* name, void (*handler)(char* args)); +void shell_init(shell_t *shell, const shell_command_t *shell_commands, int(*read_char)(void), void (*put_char)(int)); /** * @brief Endless loop that waits for command and executes handler. diff --git a/sys/include/shell_commands.h b/sys/include/shell_commands.h new file mode 100644 index 000000000..22efd8dfb --- /dev/null +++ b/sys/include/shell_commands.h @@ -0,0 +1,14 @@ +#ifndef __SHELL_COMMANDS_H +#define __SHELL_COMMANDS_H + +#include + +#define DISK_GET_SECTOR_SIZE "dget_ssize" +#define DISK_GET_SECTOR_COUNT "dget_scount" +#define DISK_GET_BLOCK_SIZE "dget_bsize" +#define DISK_READ_SECTOR_CMD "dread_sec" +#define DISK_READ_BYTES_CMD "dread" + +extern const shell_command_t _shell_command_list[]; + +#endif /* __SHELL_COMMANDS_H */ diff --git a/sys/include/swtimer.h b/sys/include/swtimer.h index 1ff56320c..b1962d524 100644 --- a/sys/include/swtimer.h +++ b/sys/include/swtimer.h @@ -17,6 +17,7 @@ #ifndef __SWTIMER_H__ #define __SWTIMER_H__ +#warning Swtimers are deprecated. use virtual timers (vtimer) instead. #include @@ -28,11 +29,7 @@ #undef wakeup -//#if WORDSIZE == 32 -//typedef uint64_t swtime_t; -//#else typedef uint32_t swtime_t; -//#endif /** * A swtimer. diff --git a/sys/include/timex.h b/sys/include/timex.h new file mode 100644 index 000000000..21930b867 --- /dev/null +++ b/sys/include/timex.h @@ -0,0 +1,31 @@ +#ifndef __TIMEX_H +#define __TIMEX_H + +#include + +typedef struct timex_t { + uint32_t seconds; + uint32_t microseconds; +} timex_t; + +/* a+b */ +timex_t timex_add(const timex_t a, const timex_t b); + +/* a-b*/ +timex_t timex_sub(const timex_t a, const timex_t b); + +timex_t timex_set(uint32_t seconds, uint32_t microseconds); + +/** + * @brief Compares two timex values. + * + * @return -1 when a is smaller, 0 if equal, 1 if a is bigger + */ +timex_t timex_sub(const timex_t a, const timex_t b); + +/** + * @brief Corrects timex_t structure so that microseconds < 1000000 + */ +void timex_normalize(timex_t *time); + +#endif /* __TIMEX_H */ diff --git a/sys/include/transceiver.h b/sys/include/transceiver.h new file mode 100644 index 000000000..3e528aeba --- /dev/null +++ b/sys/include/transceiver.h @@ -0,0 +1,91 @@ +#ifndef TRANSCEIVER_H +#define TRANSCEIVER_H + +#include + +/* Stack size for transceiver thread */ +#ifdef ENABLE_DEBUG +#define TRANSCEIVER_STACK_SIZE (2048) +#else +#define TRANSCEIVER_STACK_SIZE (512) +#endif + +/* The maximum of threads to register */ +#define TRANSCEIVER_MAX_REGISTERED (4) + +/* The size of the message queue between driver and transceiver (must be power + * of two */ +#define TRANSCEIVER_MSG_BUFFER_SIZE (32) + +/** + * @brief Message types for transceiver interface + */ +enum transceiver_msg_type_t { + /* Packet types for driver <-> transceiver communication */ + RCV_PKT_CC1020, ///< packet was received by CC1020 transceiver + RCV_PKT_CC1100, ///< packet was received by CC1100 transceiver + + /* Packet types for transceiver <-> upper layer communication */ + PKT_PENDING, ///< packet pending in transceiver buffer + SND_PKT, ///< request for sending a packet + SND_ACK, ///< request for sending an acknowledgement + SWITCH_RX, ///< switch transceiver to RX sate + POWERDOWN, ///< power down transceiver + GET_CHANNEL, ///< Get current channel + SET_CHANNEL, ///< Set a new channel + GET_ADDRESS, ///< Get the radio address + SET_ADDRESS, ///< Set the radio address + SET_MONITOR, ///< Set transceiver to monitor mode (disable address checking) + + /* Error messages */ + ENOBUFFER, ///< No buffer left +}; + +/** + * @brief All supported transceivers + */ +typedef enum { + TRANSCEIVER_NONE, ///< Invalid + TRANSCEIVER_CC1100, ///< CC110X transceivers + TRANSCEIVER_CC1020 ///< CC1020 transceivers +} transceiver_type_t; + +/** + * @brief Manage registered threads per transceiver + */ +typedef struct { + transceiver_type_t transceivers; ///< the tranceivers the thread is registered for + int pid; ///< the thread's pid +} registered_t; + +typedef struct { + transceiver_type_t transceivers; + void *data; +} transceiver_command_t;; + +/* The transceiver thread's pid */ +extern int transceiver_pid; + +/** + * @brief Initializes the transceiver module for certain transceiver types + * + * @param transceivers Specifies all transceivers to init + **/ +void transceiver_init(transceiver_type_t transceivers); + +/** + * @brief Runs the transceiver thread + */ +int transceiver_start(void); + +/** + * @brief register a thread for events from certain transceivers + * + * @param transceivers The transceiver types to register for + * @param pid The pid of the thread to register + * + * return 1 on success, 0 otherwise + */ +uint8_t transceiver_register(transceiver_type_t transceivers, int pid); + +#endif /* TRANSCEIVER_H */ diff --git a/sys/include/vtimer.h b/sys/include/vtimer.h new file mode 100644 index 000000000..2a5d7a0d9 --- /dev/null +++ b/sys/include/vtimer.h @@ -0,0 +1,94 @@ +/** \addtogroup system + * @{ */ + +/** + * \defgroup vtimer Virtual (Software) Timer library + * + * The vtimer library provides functions for setting, resetting and restarting + * software timers, and for checking if a vtimer has expired. + * + * (As of now, not resetting, restarting, removing and checking are not implemented) + * + * @{ + */ + +/** + * \file + * Timer library header file. + */ +#ifndef __VTIMER_H +#define __VTIMER_H + +#include +#include + +#define MSG_TIMER 12345 + +/** + * A vtimer object. + * + * This structure is used for declaring a vtimer. This should not be used by programmers, use the vtimer_set_*-functions instead. + * + * \hideinitializer + */ +typedef struct vtimer_t { + queue_node_t queue_entry; + timex_t absolute; + void(*action)(void*); + void* arg; + unsigned int pid; +} vtimer_t; + +/** + * @brief Current system time + * @return Time as timex_t since system boot + */ +timex_t vtimer_now(); + +/** + * @brief Initializes the vtimer subsystem. To be called once at system initialization. Will be initialized by auto_init. + * + * @return always 0 + */ +int vtimer_init(); + +/** + * @brief will cause the calling thread to be suspended from excecution until the number of microseconds has elapsed + * @param[in] us number of microseconds + * @return 0 on success, < 0 on error + */ +int vtimer_usleep(uint32_t us); + +/** + * @brief will cause the calling thread to be suspended from excecution until the time specified by time has elapsed + * @param[in] time timex_t with time to suspend execution + * @return 0 on success, < 0 on error + */ +int vtimer_sleep(timex_t time); + +/** + * @brief set a vtimer with msg event handler + * @param[in] t pointer to preinitialised vtimer_t + * @param[in] interval vtimer timex_t interval + * @param[in] pid process id + * @param[in] ptr message value + * @return 0 on success, < 0 on error + */ +int vtimer_set_msg(vtimer_t *t, timex_t interval, unsigned int pid, void *ptr); + +/** + * @brief set a vtimer with wakeup event + * @param[in] t pointer to preinitialised vtimer_t + * @param[in] pid process id + * @return 0 on success, < 0 on error + */ +int vtimer_set_wakeup(vtimer_t *t, timex_t interval, int pid); + +/** + * @brief remove a vtimer + * @param[in] t pointer to preinitialised vtimer_t + * @return 0 on success, < 0 on error + */ +int vtimer_remove(vtimer_t *t); + +#endif /* __VTIMER_H */ diff --git a/sys/lib/ringbuffer.c b/sys/lib/ringbuffer.c index ef2116d5a..4e021942d 100755 --- a/sys/lib/ringbuffer.c +++ b/sys/lib/ringbuffer.c @@ -8,7 +8,7 @@ //#define DEBUG(...) printf (__VA_ARGS__) #define DEBUG(...) -void ringbuffer_init(ringbuffer *rb, char* buffer, unsigned int bufsize) { +void ringbuffer_init(ringbuffer_t *rb, char* buffer, unsigned int bufsize) { rb->buf = buffer; rb->start = 0; rb->end = 0; @@ -16,13 +16,13 @@ void ringbuffer_init(ringbuffer *rb, char* buffer, unsigned int bufsize) { rb->avail = 0; } -void rb_add_elements(ringbuffer* rb, char *buf, int n) { +void rb_add_elements(ringbuffer_t* rb, char *buf, int n) { for (int i = 0; i < n; i++) { rb_add_element(rb, buf[i]); } } -void rb_add_element(ringbuffer* rb, char c) { +void rb_add_element(ringbuffer_t* rb, char c) { if (rb->avail == rb->size) rb_get_element(rb); rb->buf[rb->end++] = c; @@ -31,7 +31,7 @@ void rb_add_element(ringbuffer* rb, char c) { rb->avail++; } -int rb_get_element(ringbuffer *rb) { +int rb_get_element(ringbuffer_t *rb) { if (rb->avail == 0) return -1; rb->avail--; @@ -42,7 +42,7 @@ int rb_get_element(ringbuffer *rb) { return c; } -int rb_get_elements(ringbuffer *rb, char* buf, int n) { +int rb_get_elements(ringbuffer_t *rb, char* buf, int n) { int count = 0; while (rb->avail && (count < n)) { buf[count++] = rb_get_element(rb); diff --git a/sys/lib/ringbuffer.h b/sys/lib/ringbuffer.h index 11f7222af..3e646ae79 100755 --- a/sys/lib/ringbuffer.h +++ b/sys/lib/ringbuffer.h @@ -7,12 +7,12 @@ typedef struct ringbuffer { unsigned int end; unsigned int size; unsigned int avail; -} ringbuffer; +} ringbuffer_t; -void ringbuffer_init(ringbuffer *rb, char* buffer, unsigned int bufsize); -void rb_add_element(ringbuffer *rb, char c); -void rb_add_elements(ringbuffer *rb, char *buf, int n); -int rb_get_element(ringbuffer *rb); -int rb_get_elements(ringbuffer *rb, char *buf, int n); +void ringbuffer_init(ringbuffer_t *rb, char* buffer, unsigned int bufsize); +void rb_add_element(ringbuffer_t *rb, char c); +void rb_add_elements(ringbuffer_t *rb, char *buf, int n); +int rb_get_element(ringbuffer_t *rb); +int rb_get_elements(ringbuffer_t *rb, char *buf, int n); #endif /* __RINGBUFFER_H */ diff --git a/sys/posix_io.c b/sys/posix_io.c index fd423e165..63ec13621 100644 --- a/sys/posix_io.c +++ b/sys/posix_io.c @@ -4,7 +4,7 @@ static int _posix_fileop(int pid, int op, int flags) { - msg m; + msg_t m; m.type = op; m.content.value = flags; msg_send_receive(&m, &m, pid); @@ -12,11 +12,11 @@ static int _posix_fileop(int pid, int op, int flags) { } static int _posix_fileop_data(int pid, int op, char* buffer, int nbytes) { - struct posix_iop r; + struct posix_iop_t r; r.nbytes = nbytes; r.buffer = buffer; - msg m; + msg_t m; m.type = op; m.content.ptr = (char*) &r; diff --git a/sys/shell/Jamfile b/sys/shell/Jamfile index 195b04fd8..c91c6d86a 100644 --- a/sys/shell/Jamfile +++ b/sys/shell/Jamfile @@ -28,7 +28,7 @@ SubDir TOP sys shell ; Module shell : shell.c ; -Module shell_commands : shell_commands.c : shell ; +Module shell_commands : shell_commands.c id.c rtc.c sht11.c ltc4150.c cc1100.c cc110x_ng.c disk.c : shell ; Module ps : ps.c ; diff --git a/sys/shell/cc1100.c b/sys/shell/cc1100.c new file mode 100644 index 000000000..b9542e3b7 --- /dev/null +++ b/sys/shell/cc1100.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include + +#ifdef MODULE_CC110X + +void _cc110x_get_set_address_handler(char *addr) { + int16_t a; + + a = atoi(addr+5); + if (strlen(addr) > 5) { + printf("[cc110x] Setting address %i ... ", a); + cc1100_set_address((radio_address_t)a); + if (cc1100_get_address() == (radio_address_t)a) { + puts("[OK]"); + } else { + puts("Error!"); + } + } + else { + printf("[cc1100] Got address: %i\n", cc1100_get_address()); + } +} + +void _cc110x_get_set_channel_handler(char *addr) { + int16_t a; + + a = atoi(addr+5); + if (strlen(addr) > 5) { + printf("[cc110x] Setting channel %i...", a); + cc1100_set_channel(a); + if (cc1100_get_channel() == a) { + puts("OK"); + } else { + puts("Error!"); + } + } + else { + printf("[cc1100] Got address: %i\n", cc1100_get_channel()); + } +} +#endif diff --git a/sys/shell/cc110x_ng.c b/sys/shell/cc110x_ng.c new file mode 100644 index 000000000..ed9aa4511 --- /dev/null +++ b/sys/shell/cc110x_ng.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include + +#define TEXT_SIZE CC1100_MAX_DATA_LENGTH + +char text_msg[TEXT_SIZE]; +msg_t mesg; +transceiver_command_t tcmd; + +void _cc110x_ng_get_set_address_handler(char *addr) { + int16_t a; + + tcmd.transceivers = TRANSCEIVER_CC1100; + tcmd.data = &a; + mesg.content.ptr = (char*) &tcmd; + a = atoi(addr+5); + if (strlen(addr) > 5) { + printf("[cc110x] Trying to set address %i\n", a); + mesg.type = SET_ADDRESS; + } + else { + mesg.type = GET_ADDRESS; + } + msg_send_receive(&mesg, &mesg, transceiver_pid); + printf("[cc110x] Got address: %i\n", a); +} + +void _cc110x_ng_get_set_channel_handler(char *chan) { + int16_t c; + + tcmd.transceivers = TRANSCEIVER_CC1100; + tcmd.data = &c; + mesg.content.ptr = (char*) &tcmd; + c = atoi(chan+5); + if (strlen(chan) > 5) { + printf("[cc110x] Trying to set channel %i\n", c); + mesg.type = SET_CHANNEL; + } + else { + mesg.type = GET_CHANNEL; + } + msg_send_receive(&mesg, &mesg, transceiver_pid); + printf("[cc110x] Got channel: %i\n", c); +} + +void _cc110x_ng_send_handler(char *pkt) { + radio_packet_t p; + uint32_t response; + uint16_t addr; + char *tok; + + tcmd.transceivers = TRANSCEIVER_CC1100; + tcmd.data = &p; + + tok = strtok(pkt+7, " "); + if (tok) { + addr = atoi(tok); + tok = strtok(NULL, " "); + if (tok) { + memset(text_msg, 0, TEXT_SIZE); + memcpy(text_msg, tok, strlen(tok)); + /* if (sscanf(pkt, "txtsnd %hu %s", &(addr), text_msg) == 2) {*/ + p.data = (uint8_t*) text_msg; + p.length = strlen(text_msg) + 1; + p.dst = addr; + mesg.type = SND_PKT; + mesg.content.ptr = (char*) &tcmd; + printf("[cc110x] Sending packet of length %u to %hu: %s\n", p.length, p.dst, (char*) p.data); + msg_send_receive(&mesg, &mesg, transceiver_pid); + response = mesg.content.value; + printf("[cc110x] Packet sent: %lu\n", response); + return; + } + } + puts("Usage:\ttxtsnd "); +} + +void _cc110x_ng_monitor_handler(char *mode) { + unsigned int m; + + tcmd.transceivers = TRANSCEIVER_CC1100; + tcmd.data = &m; + mesg.content.ptr = (char*) &tcmd; + m = atoi(mode+8); + if (strlen(mode) > 8) { + printf("Setting monitor mode: %u\n", m); + mesg.type = SET_MONITOR; + msg_send(&mesg, transceiver_pid, 1); + } + else { + puts("Usage:\nmonitor "); + } +} diff --git a/sys/shell/disk.c b/sys/shell/disk.c new file mode 100644 index 000000000..8d6a830f8 --- /dev/null +++ b/sys/shell/disk.c @@ -0,0 +1,123 @@ +#include +#include +#include + +#include "shell_commands.h" +#include "diskio.h" + +static inline uint8_t sector_read(unsigned char *read_buf, unsigned long sector, unsigned long length, unsigned long offset) { + unsigned long i; + if (MCI_read(read_buf, sector, 1) == RES_OK) { + printf("[disk] Read sector %lu (%lu):\n", sector, offset); + for (i = offset + 1; i <= offset + length; i++) { + printf(" %u", read_buf[i-1]); + if (!(i % 16)) { + puts(""); + } + } + puts(""); + return 1; + } + return 0; +} + +void _get_sectorsize(char *unused) { + unsigned short ssize; + if (MCI_ioctl(GET_SECTOR_SIZE, &ssize) == RES_OK) { + printf("[disk] sector size is %u\n", ssize); + } + else { + puts("[disk] Failed to fetch sector size. Card inserted?"); + } +} + +void _get_blocksize(char *unused) { + unsigned long bsize; + if (MCI_ioctl(GET_BLOCK_SIZE, &bsize) == RES_OK) { + printf("[disk] block size is %lu\n", bsize); + } + else { + puts("[disk] Failed to fetch block size. Card inserted?"); + } +} + +void _get_sectorcount(char *unused) { + unsigned long scount; + if (MCI_ioctl(GET_SECTOR_COUNT, &scount) == RES_OK) { + printf("[disk] sector count is %lu\n", scount); + } + else { + puts("[disk] Failed to fetch sector count. Card inserted?"); + } +} + +void _read_sector(char *sector) { + unsigned long sectornr, scount; + unsigned short ssize; + + if (strlen(sector) > strlen(DISK_READ_SECTOR_CMD) + 1) { + + sectornr = atol(sector + strlen(DISK_READ_SECTOR_CMD) + 1); + if ((MCI_ioctl(GET_SECTOR_COUNT, &scount) == RES_OK) && (MCI_ioctl(GET_SECTOR_SIZE, &ssize) == RES_OK)) { + unsigned char read_buf[ssize]; + if (sector_read(read_buf, sectornr, ssize, 0)) { + return; + } + } + printf("[disk] Error while reading sector %lu\n", sectornr); + } + else { + printf("[disk] Usage:\n%s \n", DISK_READ_SECTOR_CMD); + return; + } +} + +void _read_bytes(char *bytes) { + unsigned long sector = 1, scount, offset; + unsigned short ssize, length; + char *tok; + + /* tokenize user input */ + tok = strtok(bytes + strlen(DISK_READ_BYTES_CMD) + 1, " "); + if (tok) { + offset = atol(tok); + tok = strtok(NULL, " "); + if (tok) { + length = atoi(tok); + if (length) { + /* get card info */ + if ((MCI_ioctl(GET_SECTOR_COUNT, &scount) == RES_OK) && (MCI_ioctl(GET_SECTOR_SIZE, &ssize) == RES_OK)) { + /* calculate sector and offset position */ + sector = (offset / ssize) + 1; + offset = (offset % ssize); + /* preapre buffer (size must be a multiple of sector size) */ + unsigned char read_buf[((length / ssize) + 1) * 512]; + /* read from several sectors */ + if (length > (ssize - offset)) { + /* buffer offset */ + unsigned long j = 0; + /* chunk from current sector */ + unsigned short tmp = ssize - offset; + while (length) { + sector_read(read_buf + j, sector++, tmp, offset); + /* decrease length and recalculate chunk */ + length -= tmp; + tmp = (length >= ssize) ? ssize : length; + } + + return; + } /* length > (ssize - offset) */ + /* read only one sector */ + else { + if (sector_read(read_buf, sector, length, offset)) { + return; + } + } /* length < (ssize - offset) */ + } /* ioctl */ + printf("[disk] Error while reading sector %lu\n", sector); + return; + } /* length */ + } /* strtok #2 */ + } /* strtok #1 */ + printf("[disk] Usage:\n%s \n", DISK_READ_BYTES_CMD); +} diff --git a/sys/shell/id.c b/sys/shell/id.c new file mode 100644 index 000000000..3807484ff --- /dev/null +++ b/sys/shell/id.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +void _id_handler(char *id) { + long newid; + + newid = atoi(id+3); + if (strlen(id) < 3) { +#ifdef MODULE_CONFIG + printf("Current id: %u\n", sysconfig.id); +#endif + } + else { + printf("Setting new id %lu\n", newid); +#ifdef MODULE_CONFIG + sysconfig.id = newid; + if (!config_save()) { + puts("ERROR setting new id"); + } +#endif + } +} diff --git a/sys/shell/ltc4150.c b/sys/shell/ltc4150.c new file mode 100644 index 000000000..c29519c14 --- /dev/null +++ b/sys/shell/ltc4150.c @@ -0,0 +1,10 @@ +#include +#include + +void _get_current_handler(char* unused) { + printf("Power usage: %.4f mA (%.4f mA avg/ %.4f mAh total / %i usec)\n", ltc4150_get_current_mA(), ltc4150_get_avg_mA(), ltc4150_get_total_mAh(), ltc4150_get_interval()); +} + +void _reset_current_handler(char* unused) { + ltc4150_start(); +} diff --git a/sys/shell/ps.c b/sys/shell/ps.c index a54c8bc35..6c3226fea 100644 --- a/sys/shell/ps.c +++ b/sys/shell/ps.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include /* list of states copied from tcb.h */ @@ -27,7 +27,7 @@ void thread_print_all(void) printf("\tpid | %-21s| %-9sQ | pri | stack ( used) location | runtime | switches \n", "name", "state"); for( i = 0; i < MAXTHREADS; i++ ) { - tcb* p = (tcb*)fk_threads[i]; + tcb_t* p = (tcb_t*)sched_threads[i]; if( p != NULL ) { int state = p->status; // copy state @@ -42,7 +42,7 @@ void thread_print_all(void) switches = pidlist[i].schedules; #endif overall_stacksz += stacksz; - stacksz -= fk_measure_stack_free(p->stack_start); + stacksz -= thread_measure_stack_usage(p->stack_start); printf("\t%3u | %-21s| %-8s %.1s | %3i | %5i (%5i) %p | %6.3f%% | %8i\n", p->pid, p->name, sname, queued, p->priority, p->stack_size, stacksz, p->stack_start, runtime, switches); } diff --git a/sys/shell/rtc.c b/sys/shell/rtc.c new file mode 100644 index 000000000..74550f81e --- /dev/null +++ b/sys/shell/rtc.c @@ -0,0 +1,50 @@ +#include +#include +#include + +#ifdef MODULE_RTC +#include + +void _gettime_handler(void) { + struct tm now; + rtc_get_localtime(&now); + + printf("%s", asctime(&now)); +} + +void _settime_handler(char* c) { + struct tm now; + int res; + uint16_t month, epoch_year; + + res = sscanf(c, "date %hu-%hu-%u %u:%u:%u", + &epoch_year, + &month, + (unsigned int*) &(now.tm_mday), + (unsigned int*) &(now.tm_hour), + (unsigned int*) &(now.tm_min), + (unsigned int*) &(now.tm_sec)); + + if (res < 6) { + printf("Usage: date YYYY-MM-DD hh:mm:ss\n"); + return; + } + else { + puts("OK"); + } + + now.tm_year = epoch_year - 1900; + now.tm_mon = month - 1; + rtc_set_localtime(&now); +} + +void _date_handler(char* c) { + if (strlen(c) == 4) { + _gettime_handler(); + } + else { + _settime_handler(c); + } +} + +#endif diff --git a/sys/shell/shell.c b/sys/shell/shell.c index f306bec5a..efebc5d02 100644 --- a/sys/shell/shell.c +++ b/sys/shell/shell.c @@ -41,26 +41,61 @@ and the mailinglist (subscription via web site) * @author Kaspar Schleiser */ -#include +//#include #include #include -#include -#include #include +#include +#include +#include static void(*find_handler(const shell_command_t *command_list, char *command))(char*) { - const shell_command_t *entry = command_list; - - while(entry->name != NULL) { + const shell_command_t* entry = command_list; + if (entry) { + while (entry->name != NULL) { + if ( strcmp(entry->name, command) == 0) { + return entry->handler; + } else { + entry++; + } + } + } + +#ifdef MODULE_SHELL_COMMANDS + entry = _shell_command_list; + while (entry->name != NULL) { if ( strcmp(entry->name, command) == 0) { return entry->handler; } else { entry++; } } +#endif return NULL; } +static void print_help(const shell_command_t *command_list) { + const shell_command_t *entry = command_list; + + printf("%-20s %s\n", "Command", "Description"); + puts("---------------------------------------"); + + if (entry) { + while (entry->name != NULL) { + printf("%-20s %s\n", entry->name, entry->desc); + entry++; + } + } + +#ifdef MODULE_SHELL_COMMANDS + entry = _shell_command_list; + while (entry->name != NULL) { + printf("%-20s %s\n", entry->name, entry->desc); + entry++; + } +#endif +} + static void handle_input_line(shell_t *shell, char* line) { char* saveptr; char* linedup = strdup(line); @@ -70,15 +105,18 @@ static void handle_input_line(shell_t *shell, char* line) { if (command) { handler = find_handler(shell->command_list, command); - if (handler) { + if (handler != NULL) { handler(line); } else { - printf("shell: command not found.\n"); + if ( strcmp("help", command) == 0) { + print_help(shell->command_list); + } else { + puts("shell: command not found."); + } } } - + free(linedup); - free(line); } int readline(shell_t *shell, char* buf, int size) { @@ -111,12 +149,15 @@ void shell_run(shell_t *shell) { shell->put_char('>'); int res = readline(shell, line_buf, sizeof(line_buf)); if (! res ) { - handle_input_line(shell, strdup(line_buf)); + char* line_copy = strdup(line_buf); + handle_input_line(shell, line_copy); + free(line_copy); } } } -void shell_init(shell_t *shell, int(*readchar)(void), void(*put_char)(int)) { +void shell_init(shell_t *shell, const shell_command_t *shell_commands, int(*readchar)(void), void(*put_char)(int)) { + shell->command_list = shell_commands; shell->readchar = readchar; shell->put_char = put_char; } diff --git a/sys/shell/shell_commands.c b/sys/shell/shell_commands.c index 5223597d6..e739f723a 100644 --- a/sys/shell/shell_commands.c +++ b/sys/shell/shell_commands.c @@ -1,9 +1,88 @@ -#include +#include +#include + +extern void _id_handler(char* id); + +#ifdef MODULE_PS +extern void _ps_handler(char* unused); +#endif + +#ifdef MODULE_RTC +extern void _date_handler(char* now); +#endif + +#ifdef MODULE_SHT11 +extern void _get_temperature_handler(char* unused); +extern void _get_humidity_handler(char* unused); +extern void _get_weather_handler(char* unused); +extern void _set_offset_handler(char* offset); +#endif + +#ifdef MODULE_LTC4150 +extern void _get_current_handler(char* unused); +extern void _reset_current_handler(char* unused); +#endif + +#ifdef MODULE_CC110X +extern void _cc110x_get_set_address_handler(char *addr); +extern void _cc110x_get_set_channel_handler(char *addr); +#endif + +#ifdef MODULE_TRANSCEIVER +#ifdef MODULE_CC110X_NG +extern void _cc110x_ng_get_set_address_handler(char *addr); +extern void _cc110x_ng_get_set_channel_handler(char *chan); +extern void _cc110x_ng_send_handler(char *pkt); +extern void _cc110x_ng_monitor_handler(char *mode); +#endif +#endif + +#ifdef MODULE_MCI +extern void _get_sectorsize(char *unused); +extern void _get_blocksize(char* unused); +extern void _get_sectorcount(char* unused); +extern void _read_sector(char* sector); +extern void _read_bytes(char* bytes); +extern void _write_bytes(char* bytes); +#endif const shell_command_t _shell_command_list[] = { + {"id", "Gets or sets the node's id.", _id_handler}, #ifdef MODULE_PS - {"ps", ps_handler}, + {"ps", "Prints information about running threads.", _ps_handler}, +#endif +#ifdef MODULE_RTC + {"date", "Gets or sets current date and time.", _date_handler}, +#endif +#ifdef MODULE_SHT11 + {"temp", "Prints measured temperature.", _get_temperature_handler}, + {"hum", "Prints measured humidity.", _get_humidity_handler}, + {"weather", "Prints measured humidity and temperature.", _get_weather_handler}, + {"offset", "Set temperature offset.", _set_offset_handler}, +#endif +#ifdef MODULE_LTC4150 + {"cur", "Prints current and average power consumption.", _get_current_handler}, + {"rstcur", "Resets coulomb counter.", _reset_current_handler}, +#endif +#ifdef MODULE_CC110X + {"addr", "Gets or sets the address for the CC1100 transceiver", _cc110x_get_set_address_handler}, + {"chan", "Gets or sets the channel for the CC1100 transceiver", _cc110x_get_set_channel_handler}, +#endif +#ifdef MODULE_TRANSCEIVER +#ifdef MODULE_CC110X_NG + {"addr", "Gets or sets the address for the CC1100 transceiver", _cc110x_ng_get_set_address_handler}, + {"chan", "Gets or sets the channel for the CC1100 transceiver", _cc110x_ng_get_set_channel_handler}, + {"txtsnd", "Sends a text message to a given node via the CC1100 transceiver", _cc110x_ng_send_handler}, + {"monitor", "Enables or disables address checking for the CC1100 transceiver", _cc110x_ng_monitor_handler}, +#endif +#endif +#ifdef MODULE_MCI + {DISK_READ_SECTOR_CMD, "Reads the specified sector of inserted memory card", _read_sector}, + {DISK_READ_BYTES_CMD, "Reads the specified bytes from inserted memory card", _read_bytes}, + {DISK_GET_SECTOR_SIZE, "Get the sector size of inserted memory card", _get_sectorsize}, + {DISK_GET_SECTOR_COUNT, "Get the sector count of inserted memory card", _get_sectorcount}, + {DISK_GET_BLOCK_SIZE, "Get the block size of inserted memory card", _get_blocksize}, #endif - {NULL, NULL} + {NULL, NULL, NULL} }; diff --git a/sys/shell/sht11.c b/sys/shell/sht11.c new file mode 100644 index 000000000..b3f21ddb3 --- /dev/null +++ b/sys/shell/sht11.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include + +#ifdef MODULE_SHT11 + +extern float sht11_temperature_offset; + +void _get_humidity_handler(char* unused) { + uint8_t success; + sht11_val_t sht11_val; + success = sht11_read_sensor(&sht11_val, HUMIDITY|TEMPERATURE); + if (!success) { + printf("Error reading SHT11\n"); + } + else { + printf("Relative humidity: %5.2f%% / Temperature compensated humidity; %5.2f%%\n", + sht11_val.relhum, sht11_val.relhum_temp); + } +} +void _get_temperature_handler(char* unused) { + uint8_t success; + sht11_val_t sht11_val; + success = sht11_read_sensor(&sht11_val, TEMPERATURE); + if (!success) { + printf("Error reading SHT11\n"); + } + else { + printf("Temperature: %-6.2f°C\n", sht11_val.temperature); + } +} +void _get_weather_handler(char* unused) { + uint8_t success; + sht11_val_t sht11_val; + success = sht11_read_sensor(&sht11_val, HUMIDITY|TEMPERATURE); + if (!success) { + printf("Error reading SHT11\n"); + } + else { + printf("Relative humidity: %5.2f%% / Temperature compensated humidity; %5.2f%% ", + sht11_val.relhum, sht11_val.relhum_temp); + printf("Temperature: %-6.2f°C\n", sht11_val.temperature); + } +} + +void _set_offset_handler(char* offset) { + if (strlen(offset) == 6) { + puts("Usage: offset "); + } + else { + sscanf(offset, "offset %f", &sht11_temperature_offset); + printf("Temperature offset set to %f\n", sht11_temperature_offset); + } +} + +#endif diff --git a/sys/swtimer.c b/sys/swtimer.c index 0d87b9758..4dc248515 100644 --- a/sys/swtimer.c +++ b/sys/swtimer.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include @@ -235,7 +235,7 @@ static void swtimer_action(swtimer_t *swtimer) { } case SWTIMER_MSG: { - msg m; + msg_t m; m.content.value = swtimer->action.msg.value; int result = msg_send_int(&m, swtimer->action.msg.target_pid); if (result < 0) { diff --git a/sys/timex.c b/sys/timex.c new file mode 100644 index 000000000..40c84cfb7 --- /dev/null +++ b/sys/timex.c @@ -0,0 +1,49 @@ +#include + +timex_t timex_add(const timex_t a, const timex_t b) { + timex_t result; + result.seconds = a.seconds + b.seconds; + result.microseconds = a.microseconds + b.microseconds; + + if (result.microseconds < a.microseconds) { + result.seconds++; + } + +/* if (result.microseconds > 1000000) { + result.microseconds -= 1000000; + result.seconds++; + } +*/ + return result; +} + +void timex_normalize(timex_t *time) { + time->seconds += (time->microseconds / 1000000); + time->microseconds %= 1000000; +} + +timex_t timex_set(uint32_t seconds, uint32_t microseconds) { + timex_t result; + result.seconds = seconds; + result.microseconds = microseconds; + + return result; +} + +timex_t timex_sub(const timex_t a, const timex_t b) { + timex_t result; + result.seconds = a.seconds - b.seconds; + result.microseconds = a.microseconds - b.microseconds; + + return result; +} + +int timex_cmp(const timex_t a, const timex_t b) { + if (a.seconds < b.seconds) return -1; + if (a.seconds == b.seconds) { + if (a.microseconds < b.microseconds) return -1; + if (a.microseconds == b.microseconds) return 0; + } + return 1; +} + diff --git a/sys/transceiver.c b/sys/transceiver.c new file mode 100644 index 000000000..d9b60b0af --- /dev/null +++ b/sys/transceiver.c @@ -0,0 +1,396 @@ +#include +#include +#include + +#include +#include + +#include +#include + +#define PAYLOAD_SIZE (0) + +/* supported transceivers */ +#ifdef MODULE_CC110X_NG +#include +#if (CC1100_MAX_DATA_LENGTH > PAYLOAD_SIZE) + #undef PAYLOAD_SIZE + #define PAYLOAD_SIZE (CC1100_MAX_DATA_LENGTH) +#endif +#endif + +//#define ENABLE_DEBUG (1) +#include + +/*------------------------------------------------------------------------------------*/ +/* used transceiver types */ +transceiver_type_t transceivers = TRANSCEIVER_NONE; + +/* registered upper layer threads */ +registered_t reg[TRANSCEIVER_MAX_REGISTERED]; + +/* packet buffers */ +radio_packet_t transceiver_buffer[TRANSCEIVER_BUFFER_SIZE]; +uint8_t data_buffer[TRANSCEIVER_BUFFER_SIZE * PAYLOAD_SIZE]; + +/* message buffer */ +msg_t msg_buffer[TRANSCEIVER_MSG_BUFFER_SIZE]; + +uint32_t response; ///< response bytes for messages to upper layer threads + +int transceiver_pid; ///< the transceiver thread's pid + +static volatile uint8_t rx_buffer_pos = 0; +static volatile uint8_t transceiver_buffer_pos = 0; + +/* transceiver stack */ +char transceiver_stack[TRANSCEIVER_STACK_SIZE]; + +/*------------------------------------------------------------------------------------*/ +/* function prototypes */ +static void run(void); +static void receive_packet(uint16_t type, uint8_t pos); +static void receive_cc110x_packet(radio_packet_t *trans_p); +static uint8_t send_packet(transceiver_type_t t, void *pkt); +static int16_t get_channel(transceiver_type_t t); +static int16_t set_channel(transceiver_type_t t, void *channel); +static int16_t get_address(transceiver_type_t t); +static int16_t set_address(transceiver_type_t t, void *address); +static void set_monitor(transceiver_type_t t, void *mode); +static void powerdown(transceiver_type_t t); +static void switch_to_rx(transceiver_type_t t); + +/*------------------------------------------------------------------------------------*/ +/* Transceiver init */ +void transceiver_init(transceiver_type_t t) { + uint8_t i; + for (i = 0; i < TRANSCEIVER_MAX_REGISTERED; i++) { + reg[i].transceivers = TRANSCEIVER_NONE; + reg[i].pid = 0; + } + if (t & TRANSCEIVER_CC1100) { + transceivers |= t; + } + else { + puts("Invalid transceiver type"); + } +} + +/* Start the transceiver thread */ +int transceiver_start(void) { + transceiver_pid = thread_create(transceiver_stack, TRANSCEIVER_STACK_SIZE, PRIORITY_MAIN-3, CREATE_STACKTEST, run, "Transceiver"); + if (transceiver_pid < 0) { + puts("Error creating transceiver thread"); + } + else if (transceivers & TRANSCEIVER_CC1100) { + DEBUG("Transceiver started for CC1100\n"); + cc110x_init(transceiver_pid); + } + return transceiver_pid; +} + +/* Register an upper layer thread */ +uint8_t transceiver_register(transceiver_type_t t, int pid) { + uint8_t i; + for (i = 0; ((reg[i].pid != pid) && + (i < TRANSCEIVER_MAX_REGISTERED) && + (reg[i].transceivers != TRANSCEIVER_NONE)); i++); + + if (i >= TRANSCEIVER_MAX_REGISTERED) { + return ENOMEM; + } + else { + reg[i].transceivers |= t; + reg[i].pid = pid; + DEBUG("Thread %i registered for %i\n", reg[i].pid, reg[i].transceivers); + return 1; + } +} + +/*------------------------------------------------------------------------------------*/ +/* Internal functions */ +/*------------------------------------------------------------------------------------*/ + +/* + * @brief The main thread run, receiving and processing messages in an infinite + * loop + */ +void run(void) { + msg_t m; + transceiver_command_t *cmd; + + msg_init_queue(msg_buffer, TRANSCEIVER_MSG_BUFFER_SIZE); + while (1) { + msg_receive(&m); + /* only makes sense for messages for upper layers */ + cmd = (transceiver_command_t*) m.content.ptr; + + DEBUG("Transceiver: Message received\n"); + switch (m.type) { + case RCV_PKT_CC1020: + case RCV_PKT_CC1100: + receive_packet(m.type, m.content.value); + break; + case SND_PKT: + response = send_packet(cmd->transceivers, cmd->data); + m.content.value = response; + msg_reply(&m, &m); + break; + case GET_CHANNEL: + *((int16_t*) cmd->data) = get_channel(cmd->transceivers); + msg_reply(&m, &m); + break; + case SET_CHANNEL: + *((int16_t*) cmd->data) = set_channel(cmd->transceivers, cmd->data); + msg_reply(&m, &m); + break; + case GET_ADDRESS: + *((int16_t*) cmd->data) = get_address(cmd->transceivers); + msg_reply(&m, &m); + break; + case SET_ADDRESS: + *((int16_t*) cmd->data) = set_address(cmd->transceivers, cmd->data); + msg_reply(&m, &m); + break; + case SET_MONITOR: + set_monitor(cmd->transceivers, cmd->data); + break; + case POWERDOWN: + powerdown(cmd->transceivers); + break; + case SWITCH_RX: + switch_to_rx(cmd->transceivers); + break; + default: + DEBUG("Unknown message received\n"); + break; + } + } +} + +/*------------------------------------------------------------------------------------*/ +/* + * @brief Processes a packet received by any transceiver device + * + * @param type The message type to determine which device has received the + * packet + * @param pos The current device driver's buffer position + */ +static void receive_packet(uint16_t type, uint8_t pos) { + uint8_t i = 0; + transceiver_type_t t; + rx_buffer_pos = pos; + msg_t m; + + DEBUG("Packet received\n"); + switch (type) { + case RCV_PKT_CC1020: + t = TRANSCEIVER_CC1020; + break; + case RCV_PKT_CC1100: + t = TRANSCEIVER_CC1100; + break; + default: + t = TRANSCEIVER_NONE; + break; + } + + /* search first free position in transceiver buffer */ + for (i = 0; (i < TRANSCEIVER_BUFFER_SIZE) && (transceiver_buffer[transceiver_buffer_pos].processing); i++) { + if (++transceiver_buffer_pos == TRANSCEIVER_BUFFER_SIZE) { + transceiver_buffer_pos = 0; + } + } + /* no buffer left */ + if (i >= TRANSCEIVER_BUFFER_SIZE) { + /* inform upper layers of lost packet */ + m.type = ENOBUFFER; + m.content.value = t; + } + /* copy packet and handle it */ + else { + radio_packet_t *trans_p = &(transceiver_buffer[transceiver_buffer_pos]); + m.type = PKT_PENDING; + + if (type == RCV_PKT_CC1100) { + receive_cc110x_packet(trans_p); + } + else { + puts("Invalid transceiver type"); + return; + } + } + + /* finally notify waiting upper layers + * this is done non-blocking, so packets can get lost */ + i = 0; + while (reg[i].transceivers != TRANSCEIVER_NONE) { + if (reg[i].transceivers & t) { + m.content.ptr = (char*) &(transceiver_buffer[transceiver_buffer_pos]); + DEBUG("Notify thread %i\n", reg[i].pid); + if (msg_send(&m, reg[i].pid, false) && (m.type != ENOBUFFER)) { + transceiver_buffer[transceiver_buffer_pos].processing++; + } + } + i++; + } +} + +/* + * @brief process packets from CC1100 + * + * @param trans_p The current entry in the transceiver buffer + */ +static void receive_cc110x_packet(radio_packet_t *trans_p) { + DEBUG("Handling CC1100 packet\n"); + /* disable interrupts while copying packet */ + dINT(); + cc110x_packet_t p = cc110x_rx_buffer[rx_buffer_pos].packet; + + trans_p->src = p.phy_src; + trans_p->dst = p.address; + trans_p->rssi = cc110x_rx_buffer[rx_buffer_pos].rssi; + trans_p->lqi = cc110x_rx_buffer[rx_buffer_pos].lqi; + trans_p->length = p.length - CC1100_HEADER_LENGTH; + memcpy((void*) &(data_buffer[transceiver_buffer_pos * PAYLOAD_SIZE]), p.data, CC1100_MAX_DATA_LENGTH); + eINT(); + + DEBUG("Packet %p was from %hu to %hu, size: %u\n", trans_p, trans_p->src, trans_p->dst, trans_p->length); + trans_p->data = (uint8_t*) &(data_buffer[transceiver_buffer_pos * CC1100_MAX_DATA_LENGTH]); +} + +/*------------------------------------------------------------------------------------*/ +/* + * @brief Sends a radio packet to the receiver + * + * @param t The transceiver device + * @param pkt Generic pointer to the packet + * + * @return 1 on success, 0 otherwise + */ +static uint8_t send_packet(transceiver_type_t t, void *pkt) { + uint8_t res = 0; + radio_packet_t p = *((radio_packet_t*) pkt); + cc110x_packet_t cc110x_pkt; + + switch (t) { + case TRANSCEIVER_CC1100: + cc110x_pkt.length = p.length + CC1100_HEADER_LENGTH; + cc110x_pkt.address = p.dst; + cc110x_pkt.flags = 0; + memcpy(cc110x_pkt.data, p.data, p.length); + + res = cc110x_send(&cc110x_pkt); + break; + default: + puts("Unknown transceiver"); + break; + } + return res; +} + +/*------------------------------------------------------------------------------------*/ +/* + * @brief Sets the radio channel for any transceiver device + * + * @param t The transceiver device + * @param channel The channel to be set + * + * @return The radio channel AFTER calling the set command, -1 on error + */ +static int16_t set_channel(transceiver_type_t t, void *channel) { + uint8_t c = *((uint8_t*) channel); + switch (t) { + case TRANSCEIVER_CC1100: + return cc110x_set_channel(c); + default: + return -1; + } +} + +/* + * @brief Get the radio channel of any transceiver device + * + * @param t The transceiver device + * + * @return The current radio channel of the transceiver, -1 on error + */ +static int16_t get_channel(transceiver_type_t t) { + switch (t) { + case TRANSCEIVER_CC1100: + return cc110x_get_channel(); + default: + return -1; + } +} +/*------------------------------------------------------------------------------------*/ +/* + * @brief Get the current address of transceiver device + * + * @param t The transciever device + * + * @return The configured address of the device, -1 on error + */ +static int16_t get_address(transceiver_type_t t) { + switch (t) { + case TRANSCEIVER_CC1100: + return cc110x_get_address(); + default: + return -1; + } +} + +/* + * @brief Set the address of the transceiver device + * + * @param t The transceiver device + * @param address Generic pointer to the address to set + * + * @return The new radio address of the device + */ +static int16_t set_address(transceiver_type_t t, void *address) { + radio_address_t addr = *((radio_address_t*) address); + switch (t) { + case TRANSCEIVER_CC1100: + return cc110x_set_address(addr); + default: + return -1; + } +} + +/* + * @brief Set the transceiver device into monitor mode (disabling address check) + * + * @param t The transceiver device + * @param mode 1 for enabling monitor mode, 0 for enabling address check + */ +static void set_monitor(transceiver_type_t t, void *mode) { + switch (t) { + case TRANSCEIVER_CC1100: + cc110x_set_monitor(*((uint8_t*) mode)); + break; + default: + break; + } +} +/*------------------------------------------------------------------------------------*/ +static void powerdown(transceiver_type_t t) { + switch (t) { + case TRANSCEIVER_CC1100: + cc110x_switch_to_pwd(); + break; + default: + break; + } +} + +/*------------------------------------------------------------------------------------*/ +static void switch_to_rx(transceiver_type_t t) { + switch (t) { + case TRANSCEIVER_CC1100: + cc110x_switch_to_rx(); + break; + default: + break; + } +} diff --git a/sys/uart0.c b/sys/uart0.c index e6ad35bc3..5ba90d98a 100644 --- a/sys/uart0.c +++ b/sys/uart0.c @@ -3,23 +3,27 @@ #include #include #include +#include #include -#define UART0_BUFSIZE 32 +#define UART0_BUFSIZE (32) +#define UART0_STACKSIZE (MINIMUM_STACK_SIZE + 256) -ringbuffer uart0_ringbuffer; +ringbuffer_t uart0_ringbuffer; int uart0_handler_pid; static char buffer[UART0_BUFSIZE]; -static void uart0_loop() { +static char uart0_thread_stack[UART0_STACKSIZE]; + +static void uart0_loop(void) { chardev_loop(&uart0_ringbuffer); } -void board_uart0_init() { +void board_uart0_init(void) { ringbuffer_init(&uart0_ringbuffer, buffer, UART0_BUFSIZE); - int pid = thread_create(KERNEL_CONF_STACKSIZE_MAIN, PRIORITY_MAIN-1, CREATE_STACKTEST, uart0_loop, "uart0"); + int pid = thread_create(uart0_thread_stack, sizeof(uart0_thread_stack), PRIORITY_MAIN-1, CREATE_STACKTEST, uart0_loop, "uart0"); uart0_handler_pid = pid; puts("uart0_init() [OK]"); } @@ -28,8 +32,18 @@ void uart0_handle_incoming(int c) { rb_add_element(&uart0_ringbuffer, c); } -void uart0_notify_thread() { - msg m; +void uart0_notify_thread(void) { + msg_t m; m.type = 0; msg_send_int(&m, uart0_handler_pid); } + +int uart0_readc(void) { + char c = 0; + posix_read(uart0_handler_pid, &c, 1); + return c; +} + +void uart0_putc(int c) { + putchar(c); +} diff --git a/sys/vtimer.c b/sys/vtimer.c new file mode 100644 index 000000000..85e6d5511 --- /dev/null +++ b/sys/vtimer.c @@ -0,0 +1,259 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//#define ENABLE_DEBUG +#include + +#define VTIMER_THRESHOLD 20U +#define VTIMER_BACKOFF 10U + +#define SECONDS_PER_TICK (4096U) +#define MICROSECONDS_PER_TICK (4096U * 1000000) + +void vtimer_callback(void *ptr); +void vtimer_tick(void *ptr); +static int vtimer_set(vtimer_t *timer); +static int set_longterm(vtimer_t *timer); +static int set_shortterm(vtimer_t *timer); + +#ifdef ENABLE_DEBUG +static void vtimer_print(vtimer_t* t); +#endif + +static queue_node_t longterm_queue_root; +static queue_node_t shortterm_queue_root; + +static vtimer_t longterm_tick_timer; +static uint32_t longterm_tick_start; +static volatile int in_callback = false; + +static int hwtimer_id = -1; +static uint32_t hwtimer_next_absolute; + +static uint32_t seconds = 0; + +static int set_longterm(vtimer_t *timer) { + timer->queue_entry.priority = timer->absolute.seconds; + queue_priority_add(&longterm_queue_root, (queue_node_t*)timer); + return 0; +} + +static int update_shortterm() { + if (hwtimer_id != -1) { + if (hwtimer_next_absolute != shortterm_queue_root.next->priority) { + hwtimer_remove(hwtimer_id); + } else { + return 0; + } + } + + hwtimer_next_absolute = shortterm_queue_root.next->priority; + + unsigned int next = hwtimer_next_absolute + longterm_tick_start; + unsigned int now = hwtimer_now(); + + if((next - VTIMER_THRESHOLD - now) > MICROSECONDS_PER_TICK ) { + next = now + VTIMER_BACKOFF; + } + + hwtimer_id = hwtimer_set_absolute(next, vtimer_callback, NULL); + DEBUG("update_shortterm: Set hwtimer to %lu (now=%lu)\n", hwtimer_next_absolute + longterm_tick_start, hwtimer_now()); + return 0; +} + +void vtimer_tick(void *ptr) { + DEBUG("vtimer_tick()."); + seconds += SECONDS_PER_TICK; + + longterm_tick_start = longterm_tick_timer.absolute.microseconds; + longterm_tick_timer.absolute.microseconds = longterm_tick_timer.absolute.microseconds + MICROSECONDS_PER_TICK; + set_shortterm(&longterm_tick_timer); + + while (longterm_queue_root.next) { + vtimer_t *timer = (vtimer_t*) longterm_queue_root.next; + if (timer->absolute.seconds == seconds) { + timer = (vtimer_t*) queue_remove_head(&longterm_queue_root); + set_shortterm(timer); + } else { + break; + } + } + + update_shortterm(); +} + +static int set_shortterm(vtimer_t *timer) { + DEBUG("set_shortterm(): Absolute: %lu %lu\n", timer->absolute.seconds, timer->absolute.microseconds); + timer->queue_entry.priority = timer->absolute.microseconds; + queue_priority_add(&shortterm_queue_root, (queue_node_t*)timer); + return 1; +} + +void vtimer_callback(void *ptr) { + vtimer_t *timer; + in_callback = true; + hwtimer_id = -1; + + timer = (vtimer_t *)queue_remove_head(&shortterm_queue_root); + +#ifdef ENABLE_DEBUG + vtimer_print(timer); +#endif + DEBUG("vtimer_callback(): Shooting %lu.\n", timer->absolute.microseconds); + + /* shoot timer */ + if (timer->action == (void*) msg_send_int) { + msg_t msg; + msg.type = MSG_TIMER; + msg.content.value = (unsigned int) timer->arg; + msg_send_int(&msg, timer->pid); + } else { + timer->action(timer->arg); + } + + in_callback = false; + update_shortterm(); +} + +void normalize_to_tick(timex_t *time) { + DEBUG("Normalizing: %lu %lu\n", time->seconds, time->microseconds); + uint32_t seconds_tmp = time->seconds % SECONDS_PER_TICK; + time->seconds -= seconds_tmp; + uint32_t usecs_tmp = time->microseconds + (seconds_tmp * 1000000); + DEBUG("Normalizin2: %lu %lu\n", time->seconds, usecs_tmp); + if (usecs_tmp < time->microseconds) { + usecs_tmp -= MICROSECONDS_PER_TICK; + time->seconds += SECONDS_PER_TICK; + } + if (usecs_tmp > MICROSECONDS_PER_TICK) { + usecs_tmp -= MICROSECONDS_PER_TICK; + time->seconds += SECONDS_PER_TICK; + } + time->microseconds = usecs_tmp; + DEBUG(" Result: %lu %lu\n", time->seconds, time->microseconds); +} + +static int vtimer_set(vtimer_t *timer) { + DEBUG("vtimer_set(): New timer. Offset: %lu %lu\n", timer->absolute.seconds, timer->absolute.microseconds); + + timer->absolute = timex_add(vtimer_now(), timer->absolute); + normalize_to_tick(&(timer->absolute)); + + DEBUG("vtimer_set(): Absolute: %lu %lu\n", timer->absolute.seconds, timer->absolute.microseconds); + + int result = 0; + + if (timer->absolute.seconds == 0) { + if (timer->absolute.microseconds > 10) { + timer->absolute.microseconds -= 10; + } + } + + int state = disableIRQ(); + if (timer->absolute.seconds != seconds ) { + /* we're long-term */ + DEBUG("vtimer_set(): setting long_term\n"); + result = set_longterm(timer); + } else { + DEBUG("vtimer_set(): setting short_term\n"); + if (set_shortterm(timer)) { + + /* delay update of next shortterm timer if we + * are called from within vtimer_callback. + */ + if (!in_callback) { + result = update_shortterm(); + } + } + } + + restoreIRQ(state); + + return result; +} + +timex_t vtimer_now() { + timex_t t = timex_set(seconds, hwtimer_now()-longterm_tick_start); + return t; +} + +int vtimer_init() { + DEBUG("vtimer_init().\n"); + int state = disableIRQ(); + seconds = 0; + + longterm_tick_timer.action = vtimer_tick; + longterm_tick_timer.arg = NULL; + + longterm_tick_timer.absolute.seconds = 0; + longterm_tick_timer.absolute.microseconds = MICROSECONDS_PER_TICK; + + DEBUG("vtimer_init(): Setting longterm tick to %lu\n", longterm_tick_timer.absolute.microseconds); + + set_shortterm(&longterm_tick_timer); + update_shortterm(); + + restoreIRQ(state); + return 0; +} + +int vtimer_set_wakeup(vtimer_t *t, timex_t interval, int pid) { + t->action = (void*) thread_wakeup; + t->arg = (void*) pid; + t->absolute = interval; + t->pid = 0; + vtimer_set(t); + return 0; +} + +int vtimer_usleep(uint32_t usecs) { + timex_t offset = timex_set(0, usecs); + return vtimer_sleep(offset); +} + +int vtimer_sleep(timex_t time) { + vtimer_t t; + vtimer_set_wakeup(&t, time, thread_getpid()); + thread_sleep(); + return 0; +} + +int vtimer_remove(vtimer_t *t){ + queue_remove(&shortterm_queue_root, (queue_node_t*)t); + queue_remove(&longterm_queue_root, (queue_node_t*)t); + + update_shortterm(); + + if (! inISR() ) eINT(); + return 0; +} + +int vtimer_set_msg(vtimer_t *t, timex_t interval, unsigned int pid, void *ptr){ + t->action = (void* ) msg_send_int; + t->arg = ptr; + t->absolute = interval; + t->pid = pid; + vtimer_set(t); + return 0; +} + +#ifdef ENABLE_DEBUG +static void vtimer_print(vtimer_t* t) { + printf("Seconds: %lu - Microseconds: %lu\n \ + action: %p\n \ + action: %p\n \ + pid: %u\n", + t->absolute.seconds, t->absolute.microseconds, + t->action, + t->arg, + t->pid); +} +#endif diff --git a/tools/pyterm/pyterm.py b/tools/pyterm/pyterm.py new file mode 100755 index 000000000..9170173cb --- /dev/null +++ b/tools/pyterm/pyterm.py @@ -0,0 +1,149 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import cmd, serial, sys, threading, readline, time, ConfigParser, logging, os + +pytermdir = os.environ['HOME'] + os.path.sep + '.pyterm' + +class SerCmd(cmd.Cmd): + + def __init__(self, port=None): + cmd.Cmd.__init__(self) + self.port = port + self.aliases = dict() + self.load_config() + try: + readline.read_history_file() + except IOError: + pass + + ### create Logging object + my_millis = ("%.4f" % time.time()) + date_str = '%s.%s' % (time.strftime('%Y%m%d-%H:%M:%S'), my_millis[-4:]) + # create formatter + fmt_str = '%(asctime)s - %(levelname)s # %(message)s' + formatter = logging.Formatter(fmt_str) + logging.basicConfig(filename=pytermdir + os.path.sep + date_str + '.log', level=logging.DEBUG, format=fmt_str) + ch = logging.StreamHandler() + ch.setLevel(logging.DEBUG) + + # create logger + self.logger = logging.getLogger('') + self.logger.setLevel(logging.DEBUG) + + # add formatter to ch + ch.setFormatter(formatter) + # add ch to logger + self.logger.addHandler(ch) + + + def preloop(self): + if not self.port: + sys.stderr.write("No port specified!\n") + sys.exit(-1) + self.ser = serial.Serial(port=self.port, baudrate=115200, dsrdtr=0, rtscts=0) + self.ser.setDTR(0) + self.ser.setRTS(0) + + # start serial->console thread + receiver_thread = threading.Thread(target=reader, args=(self.ser,self.logger)) + receiver_thread.setDaemon(1) + receiver_thread.start() + + def default(self, line): + for tok in line.split(';'): + tok = self.get_alias(tok) + self.ser.write(tok.strip() + "\n") + + def do_help(self, line): + self.ser.write("help\n") + + def complete_date(self, text, line, begidx, endidm): + date = time.strftime("%Y-%m-%d %H:%M:%S") + return ["%s" % date] + + def do_reset(self, line): + self.ser.setDTR(1) + self.ser.setDTR(0) + + def do_exit(self, line): + readline.write_history_file() + sys.exit(0) + + def do_save(self, line): + if not self.config.has_section("general"): + self.config.add_section("general") + self.config.set("general", "port", self.port) + if len(self.aliases): + if not self.config.has_section("aliases"): + self.config.add_section("aliases") + for alias in self.aliases: + self.config.set("aliases", alias, self.aliases[alias]) + + with open(path.expanduser('~/.pyterm'), 'wb') as config_fd: + self.config.write(config_fd) + print("Config saved") + + def do_show_config(self, line): + for key in self.__dict__: + print(str(key) + ": " + str(self.__dict__[key])) + + def do_alias(self, line): + if line.endswith("list"): + for alias in self.aliases: + print("%s = %s" % (alias, self.aliases[alias])) + return + if not line.count("="): + sys.stderr.write("Usage: alias = \n") + return + self.aliases[line.split('=')[0].strip()] = line.split('=')[1].strip() + + def do_rmalias(self, line): + if not self.aliases.pop(line, None): + sys.stderr.write("Alias not found") + + def get_alias(self, tok): + for alias in self.aliases: + if tok.split()[0] == alias: + return self.aliases[alias] + tok[len(alias):] + return tok + + def load_config(self): + self.config = ConfigParser.SafeConfigParser() + self.config.read([pytermdir + os.path.sep + 'pyterm.conf']) + + for sec in self.config.sections(): + if sec == "aliases": + for opt in self.config.options(sec): + self.aliases[opt] = self.config.get(sec, opt) + else: + for opt in self.config.options(sec): + if not self.__dict__.has_key(opt): + self.__dict__[opt] = self.config.get(sec, opt) + + +def reader(ser, logger): + output = "" + while (1): + c = ser.read(1) + if c == '\n' or c == '\r': + logger.info(output) + output = "" + else: + output += c + #sys.stdout.write(c) + #sys.stdout.flush() + +if __name__ == "__main__": + if not os.path.exists(pytermdir): + os.makedirs(pytermdir) + + if (len(sys.argv) > 1): + port = sys.argv[1] + else: + port = None + + myshell = SerCmd(port) + myshell.prompt = '' + + myshell.cmdloop("Welcome to pyterm") diff --git a/tools/toolchains/build_gnuarm_naked.sh b/tools/toolchains/build_gnuarm_naked.sh new file mode 100755 index 000000000..86a6c252a --- /dev/null +++ b/tools/toolchains/build_gnuarm_naked.sh @@ -0,0 +1,163 @@ +#!/bin/bash + +# directory to install compiled binaries into +PREFIX=${HOME}/gnuarm-naked + +# directory to download source files and store intermediates +GNUARM_BUILDDIR=${GNUARM_BUILDDIR:-"/tmp/gnuarm-naked-${USER}"} + +#GCC_VER=4.5.1 +#GCC_MD5=dc8959e31b01a65ce10d269614815054 +GCC_VER=4.3.4 +GCC_MD5=575b3220bb8e7060939c429fc8608d22 + +BINUTILS_VER=2.20.1 +BINUTILS_MD5=9cdfb9d6ec0578c166d3beae5e15c4e5 + +NEWLIB_VER=1.18.0 +NEWLIB_MD5=3dae127d4aa659d72f8ea8c0ff2a7a20 + +GDB_VER=7.2 +GDB_MD5=64260e6c56979ee750a01055f16091a5 + +#uncomment to support multi-threaded compile +MAKE_THREADS=-j4 + +DOWNLOADER=wget +DOWNLOADER_OPTS="-nv -c" + +# +# Build targets +# +FILES=. + +build_binutils() { + echo "Building binutils..." + if [ ! -e .binutils_extracted ] ; then + tar -xjf ${FILES}/binutils-${BINUTILS_VER}.tar.bz2 + touch .binutils_extracted + fi + rm -rf binutils-build && mkdir -p binutils-build && cd binutils-build && + ../binutils-${BINUTILS_VER}/configure --target=arm-elf --prefix=${PREFIX} --enable-interwork --enable-multilibi --with-float=soft --with-fpu=vfp && + make ${MAKE_THREADS} all CFLAGS=-Wformat=0 && + make install && + cd ${GNUARM_BUILDDIR} +} + +build_gcc() { + echo "Building gcc..." + if [ ! -e .gcc_extracted ] ; then + tar -xjf ${FILES}/gcc-core-${GCC_VER}.tar.bz2 && + touch .gcc_extracted + fi + rm -rf gcc-build && mkdir -p gcc-build && cd gcc-build && + ../gcc-${GCC_VER}/configure --target=arm-elf --prefix=${PREFIX} --enable-interwork --enable-multilib --enable-languages="c" --enable-lto --disable-libssp --disable-hardfloat --with-float=soft --with-fpu=vfp --without-headers && + + make ${MAKE_THREADS} all && + make install && + + cd ${GNUARM_BUILDDIR} +} + +extract_newlib() { + if [ ! -e .newlib_extracted ] ; then + echo -n "Extracting newlib..." + tar -xzf ${FILES}/newlib-${NEWLIB_VER}.tar.gz && + touch .newlib_extracted && + echo " Done." + fi +} + +build_newlib() { + cd ${GNUARM_BUILDDIR} && + + if [ ! -e .newlib_extracted ] ; then + extract_newlib + fi + + rm -rf newlib-build && mkdir -p newlib-build && cd newlib-build && + ../newlib-${NEWLIB_VER}/configure --target=arm-elf --prefix=${PREFIX} --enable-interwork --enable-multilib --disable-newlib-supplied-syscalls --enable-newlib-reent-small --enable-newlib-io-long-long --enable-newlib-io-float --with-float=soft --with-fpu=vfp && + #--enable-newlib-supplied-syscalls && + # options to try: --enable-newlib-reent-small + make ${MAKE_THREADS} TARGET_CFLAGS=-DREENTRANT_SYSCALLS_PROVIDED all && + make install && + + # generate zip-file to provide binary download + cd ${PREFIX}/arm-elf && + + # + # package compiled newlib for windows users. any new version must be uploaded to the + # webserver. see manual arm/toolchain/windows for paths and documentation. + # + zip -ru newlib-${NEWLIB_VER}.zip include sys-include lib/*.a lib/thumb/*.a + + cd ${GNUARM_BUILDDIR} +} + +build_gdb() { + echo "Building gdb..." + if [ ! -e .gdb_extracted ] ; then + tar -xjf ${FILES}/gdb-${GDB_VER}.tar.bz2 && + touch .gdb_extracted + fi + rm -rf gdb-build && mkdir -p gdb-build && cd gdb-build && + ../gdb-${GDB_VER}/configure --target=arm-elf --prefix=${PREFIX} --enable-interwork --enable-multilib && + + make ${MAKE_THREADS} all CFLAGS=-D_FORTIFY_SOURCE=0 && + make install && + + cd ${GNUARM_BUILDDIR} +} + +clean() { + echo "Cleaning up..." + rm -rf .gdb_extracted .newlib_extracted .gcc_extracted .binutils_extracted + rm -rf binutils-build gcc-build newlib-build gdb-build +} + +export PATH=$PATH:${PREFIX}/bin + +download() { + download_file http://ftp.gnu.org/gnu/binutils binutils-${BINUTILS_VER}.tar.bz2 ${BINUTILS_MD5} && + download_file ftp://ftp.fu-berlin.de/unix/languages/gcc/releases/gcc-${GCC_VER} gcc-core-${GCC_VER}.tar.bz2 ${GCC_MD5} && + download_file http://ftp.gnu.org/gnu/gdb gdb-${GDB_VER}.tar.bz2 ${GDB_MD5} +} + +download_file() { + echo "Downloading ${1}/${2}..." + ${DOWNLOADER} ${DOWNLOADER_OPTS} $1/$2 + + echo -n "Checking MD5 of " + echo "${3} ${2}" | md5sum -c - +} + +build_all() { + echo "Starting in ${GNUARM_BUILDDIR}. Installing to ${PREFIX}." + download && + build_binutils && + build_gcc && + build_gdb && + + echo "Build complete." +} + +usage() { + echo "usage: ${0} build_[binutils|gcc|newlib|gdb|all]" + echo "example: ./build_gnuarm build_all" + echo "" + echo "Builds a GNU ARM toolchain. installs to HOME/gnuarm, uses /tmp/gnuarm-USER as temp." + echo "Edit to change these directories." + echo "Run like \"MAKE_THREADS=-j4 ${0} build_all\" to speed up on multicore systems." +} + +if [ -z "${1}" ]; then + usage + exit 1 +fi + +mkdir -p ${GNUARM_BUILDDIR} + +cd ${GNUARM_BUILDDIR} + +$* +