/* * This file is part of the libopencm3 project. * * Copyright (C) 2009 Uwe Hermann * Copyright (C) 2011 Stephen Caudle * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #define _GNU_SOURCE #include #include #include #include #include #include #include "settings.h" #include "misc.h" #include "ds18b20.h" uint8_t data_count = 96; // 'a' - 1 (as the first function will at 1 to make it 'a' unsigned int random_output = 50; char data_temp[66]; /* monotonically increasing number of milliseconds from reset * overflows every 49 days if you're wondering */ volatile uint32_t system_millis; #include "rfm69.h" #include "RFM69Config.h" #include "uart.h" char serialBuffer[128]; uint8_t serialBuffer_write = 0; static void usart_setup(void) { nvic_enable_irq(NVIC_USART1_IRQ); // Setup USART1 parameters. usart_set_baudrate(USART1, 9600); usart_set_databits(USART1, 8); usart_set_parity(USART1, USART_PARITY_NONE); usart_set_stopbits(USART1, USART_STOPBITS_1); usart_set_mode(USART1, USART_MODE_TX_RX); usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE); usart_enable_rx_interrupt(USART1); // Finally enable the USART. usart_enable(USART1); } void usart1_isr(void){ serialBuffer[serialBuffer_write] = usart_recv_blocking(USART1); if(serialBuffer_write < 127){ serialBuffer_write++; } else{ serialBuffer_write = 0; } //usart_send_blocking(USART1, serialBuffer[serialBuffer_write]); //Echo back } uint8_t usart1_available(){ return serialBuffer_write; } void usart1_clear(){ serialBuffer_write = 0; } char usart1_buffer(uint8_t buf_position){ return serialBuffer[buf_position]; } //https://github.com/MrSpock/stm32f0-libopencm3-template/blob/master/main.cpp void print(const char *s) { // loop through entire string while (*s) { if ( *s == '\n') { usart_send_blocking(USART1,'\r'); //usart_send_blocking(USART1,'\n'); } usart_send_blocking(USART1,*s); s++; } usart_send_blocking(USART1,'\n'); } #ifdef GPS #include "gps.h" #endif #ifdef ADC_1 #include static uint16_t read_adc_native(uint8_t channel); static void adc_setup(void) { rcc_periph_clock_enable(RCC_ADC); rcc_periph_clock_enable(RCC_GPIOA); // rcc_periph_clock_enable(RCC_GPIOB); //gpio_mode_setup(GPIOB, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO0); gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO1); gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO2); rcc_periph_clock_enable(RCC_USART2); adc_power_off(ADC1); adc_set_clk_source(ADC1, ADC_CLKSOURCE_ADC); adc_calibrate_start(ADC1); adc_calibrate_wait_finish(ADC1); adc_set_operation_mode(ADC1, ADC_MODE_SCAN); adc_disable_external_trigger_regular(ADC1); adc_set_right_aligned(ADC1); adc_enable_temperature_sensor(); adc_set_sample_time_on_all_channels(ADC1, ADC_SMPTIME_071DOT5); adc_set_resolution(ADC1, ADC_RESOLUTION_12BIT); adc_disable_analog_watchdog(ADC1); adc_power_on(ADC1); // Wait for ADC starting up. delay_ms(800); } static uint16_t read_adc_native(uint8_t channel) { uint8_t channel_array[16]; channel_array[0] = channel; adc_set_regular_sequence(ADC1, 1, channel_array); adc_start_conversion_regular(ADC1); while (!adc_eoc(ADC1)); uint16_t temp = adc_read_regular(ADC1); return temp; } #endif static void clock_setup(void) { rcc_clock_setup_in_hsi_out_48mhz(); /* Enable GPIOC clock for LED & USARTs. */ rcc_periph_clock_enable(RCC_GPIOB); rcc_periph_clock_enable(RCC_GPIOA); /* Enable clocks for USART1. */ rcc_periph_clock_enable(RCC_USART1); } /* Called when systick fires */ void sys_tick_handler(void) { system_millis++; } /* sleep for delay milliseconds */ void delay_ms(uint32_t msec_delay) { // uint32_t wake = system_millis + msec_delay; // while (wake > system_millis); for (uint32_t i = 0; i < msec_delay; i++) { delay_us(1000); } } /* * Set up timer to fire every x milliseconds * This is a unusual usage of systick, be very careful with the 24bit range * of the systick counter! You can range from 1 to 2796ms with this. */ static void systick_setup(int xms) { /* div8 per ST, stays compatible with M3/M4 parts, well done ST */ systick_set_clocksource(STK_CSR_CLKSOURCE_EXT); /* clear counter so it starts right away */ STK_CVR = 0; systick_set_reload(rcc_ahb_frequency / 8 / 1000 * xms); systick_counter_enable(); systick_interrupt_enable(); } void systick_init(uint32_t sys_freq_mhz) { // Save system clock frequency uint32_t system_mhz = sys_freq_mhz; // Configure SysTick timer for 1us ticks systick_set_reload(sys_freq_mhz); // Reload value for 1us (based on MHz clock) systick_set_clocksource(STK_CSR_CLKSOURCE_AHB); // Use AHB clock systick_counter_enable(); systick_interrupt_disable(); // No interrupt needed for delay functionality } // Microsecond delay function void delay_us(uint32_t us) { while (us--) { // Wait until the COUNTFLAG is set while (!(STK_CSR & STK_CSR_COUNTFLAG)); } } static void gpio_setup(void) { // Setup GPIO pin GPIO8/9 on GPIO port C for LEDs. gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO4 | GPIO5); // Setup GPIO pin GPIO2 on GPIO port A for Sensor PWR. //gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO2); // Setup GPIO pins for USART1 transmit and receive. gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO6|GPIO7); // Setup USART1 TX pin as alternate function. gpio_set_af(GPIOB, GPIO_AF0, GPIO6); gpio_set_af(GPIOB, GPIO_AF0, GPIO7); gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO1); // Optionally, set PA8 initial state (low or high) gpio_clear(GPIOB, GPIO1); // Set PA8 to low } /** * Increments packet count which is transmitted in the beginning of each * packet. This function has to be called every packet which is initially * transmitted by this node. * Packet count is starting with 'a' and continues up to 'z', thereafter * it's continuing with 'b'. 'a' is only transmitted at the very first * transmission! */ void incrementPacketCount(void) { data_count++; // 98 = 'b' up to 122 = 'z' if(data_count > 122) { data_count = 98; //'b' } } /** * Packet data transmission * @param Packet length */ void transmitData(uint8_t i) { gpio_set(GPIOB, GPIO5); // LED on #ifdef GATEWAY //fprintf(fp, "rx: %s|0\r\n", data_temp); #endif // Transmit the data (need to include the length of the packet and power in dbmW) rf69_send((uint8_t*)data_temp, i, POWER_OUTPUT); //tx_packets++; #ifdef POWER_SAVING //Ensure we are in Sleep mode to save power rf69_setMode(RFM69_MODE_SLEEP); #else //Ensure we are in RX mode rf69_setMode(RFM69_MODE_RX); delay_ms(500); gpio_clear(GPIOB, GPIO5); // LED off #endif } /** * This function is called when a packet is received by the radio. It will * process the packet. */ inline void processData(uint32_t len) { uint8_t i, packet_len; for(i=0; i 57) { //printf("Error1\r\n"); break; } // 2) is the second position in array a letter // < 'a' or > 'z' then break //printf("%d\r\n", data_temp[1]); if((int)data_temp[1] < 97 || (int)data_temp[1] > 122){ //printf("Error2\r\n"); break; } #ifdef DEBUG //print("rx: %s|%d\r\n",data_temp, rf69_lastRssi()); #endif //Reduce the repeat value data_temp[0] = data_temp[0] - 1; //Now add , and end line and let string functions do the rest data_temp[i] = ','; data_temp[i+1] = '\0'; if(strstr(data_temp, NODE_ID) != 0) break; strcat(data_temp, NODE_ID); // Add ID strcat(data_temp, "]"); // Add ending packet_len = strlen((char*)data_temp); delay_ms(random_output); // Random delay to try and avoid packet collision transmitData(packet_len); break; } } void awaitData(int countdown) { uint8_t rx_len; //Clear buffer data_temp[0] = '\0'; rf69_setMode(RFM69_MODE_RX); while(countdown > 0) { // Check rx buffer if(checkRx() == 1) { gpio_set(GPIOB, GPIO4); // LED on rf69_recv(data_temp, &rx_len); data_temp[rx_len - 1] = '\0'; //rx_packets++; #ifdef DEBUG char rx_data[66]; sprintf(rx_data, "%s|%d\r\n",data_temp, rf69_lastRssi()); print(rx_data); #endif processData(rx_len); gpio_clear(GPIOB, GPIO4); // LED off } countdown--; delay_ms(100); } } static unsigned char lookup[16] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf, }; uint8_t reverse(uint8_t n) { // Reverse the top and bottom nibble then swap them. return (lookup[n&0b1111] << 4) | lookup[n>>4]; } int16_t ds18b20_read_raw_temperature(void) { uint8_t scratchpad[10]; memset(scratchpad, 0, 10 * sizeof(int)); char data_temp1[12]; int16_t temp_raw, n; ds18b20_reset(); delay_ms(1); ds18b20_write_byte(0xCC); // Skip ROM delay_ms(1); ds18b20_write_byte(0xBE); // Read Scratchpad delay_ms(1); // ds18b20_write_byte(0x33); // Read ROM // delay_ms(1); // ds18b20_write_byte(0xf0); // Read ROM // delay_ms(1); // Read all 9 bytes of the scratchpad for (int i = 0; i <= 10; i++) { // scratchpad[i] = reverse(ds18b20_read_byte()); scratchpad[i] = ds18b20_read_byte(); } data_temp1[0] = '\0'; // Log scratchpad content for debugging print("Scratchpad: "); n = sprintf(data_temp1, "0:%02X 1:%02X 2:%02X 3:%02X 4:%02X 5:%02X 6:%02X 7:%02X 8:%02X 9:%02X", scratchpad[0], scratchpad[1], scratchpad[2], scratchpad[3], scratchpad[4], scratchpad[5], scratchpad[6], scratchpad[7], scratchpad[8], scratchpad[9]); print(data_temp1); print("\n"); // Raw temperature is stored in the first two bytes uint8_t temp_lsb = scratchpad[0]; uint8_t temp_msb = scratchpad[1]; temp_raw = (temp_msb << 8) | temp_lsb; return (temp_raw * 625) / 10; // Scale to Celsius * 1000 // return 0; } int main(void) { int n; uint16_t volt1 = 0, volt2 = 0; #ifdef ADC_1 uint16_t raw_volt1 = 0; #endif uint8_t pwr_saving_mode = 0; clock_setup(); systick_init(48); // systick_setup(1); //ticks every 1ms gpio_setup(); gpio_clear(GPIOB, GPIO4); // LED off gpio_clear(GPIOB, GPIO5); // LED off usart_setup(); #ifdef GPS delay_ms(5000); setupGPS(); #endif #ifdef DEBUG // SETUP print("Starting\n"); #endif #ifdef ADC_1 adc_setup(); #endif print("RF Init Start\n"); rf69_init(); print("RF Init Done\n"); while (1) { print("In While Loop\n"); // Toggle the LED (PA9) on the board every loop. gpio_toggle(GPIOB, GPIO4); // LED on/off incrementPacketCount(); int int_temp, rssi; int_temp = rf69_readTemp(); rssi = rf69_sampleRssi(); #ifdef ADC_1 raw_volt1 = read_adc_native(0x01); volt1 = raw_volt1; delay_ms(100); volt2 = read_adc_native(0x02); #else volt1 = 0; volt2 = 0; #endif int ds_temp = 1; print("Starting DS18b20\n"); ds18b20_start_conversion(); delay_ms(750); // ds18b20_read_raw_temperature(); print("Waiting\n"); // Wait for conversion to complete delay_ms(1000); print("Reading Data\n"); int16_t temperature = ds18b20_read_raw_temperature(); print("\n"); print("Temp: "); n = sprintf(data_temp, "%d", temperature); print(data_temp); print("\n"); /* */ /* #ifdef GPS print(serialBuffer); int nav_outcome = gps_check_nav(); if (nav_outcome != 6){ setupGPS(); delay_ms(5000); } gps_get_position(); n = sprintf(data_temp, "%d%cL%ld,%ld,%ldT%dR%dV%d,%dX,%d[%s]", NUM_REPEATS, data_count, lat, lon, alt, int_temp, rssi, volt1, volt2, pwr_saving_mode, NODE_ID); #else if (data_count == 'z'){ n = sprintf(data_temp, "%d%cL%sT%d,%dR%dV%d,%dX%d[%s]", NUM_REPEATS, data_count, LOCATION_STRING, int_temp, ds_temp, rssi, volt1, volt2, pwr_saving_mode, NODE_ID); } else{ n = sprintf(data_temp, "%d%cT%dR%dV%d,%dX%d[%s]", NUM_REPEATS, data_count, int_temp, rssi, volt1, volt2, pwr_saving_mode, NODE_ID); } #endif #ifdef DEBUG print(data_temp); #endif transmitData(n); #ifdef POWER_SAVING // if (raw_volt1 > VCC_THRES_1){ // pwr_saving_mode = 0; // awaitData(TX_GAP); // } // else if (raw_volt1 > VCC_THRES_2){ // //Ideally we'll add some power saving here // pwr_saving_mode = 1; // rf69_setMode(RFM69_MODE_SLEEP); // delay_ms(60000); // } // else{ //Ideally we'll add some power saving here pwr_saving_mode = 2; rf69_setMode(RFM69_MODE_SLEEP); //delay_ms(300000); delay_ms(60000); // } #else pwr_saving_mode = 1; awaitData(TX_GAP); #endif */ delay_ms(5000); } return 0; }