Add ukhasnet.c

This commit is contained in:
smallsolar 2025-04-05 22:40:23 +00:00
commit 879f5d639a
1 changed files with 576 additions and 0 deletions

576
ukhasnet.c Normal file
View File

@ -0,0 +1,576 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#define _GNU_SOURCE
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/nvic.h>
#include <stdio.h>
#include <string.h>
#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 <libopencm3/stm32/adc.h>
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<len; i++) {
//finds the end of the packet
if(data_temp[i] != ']')
continue;
//then terminates the string, ignore everything afterwards
data_temp[i+1] = '\0';
//Check validity of string
// 1) is the first position in array a number
//printf("%d\r\n", data_temp[0]);
if((int)data_temp[0] <= 48 || (int)data_temp[0] > 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;
}