Files
bacnet_stack/ports/atmega328/main.c
T
Steve Karg 4781582204 Changed ATmega168 port to ATmega328 on Uno R3 with DFR0259 RS485 shield (#784)
* Changed ATmega168 example for ATmega328 on Arduino Uno R3 with DFR0259 RS485 shield. Added ADC interface from BDK port and mapped to some AV objects. Removed MS/TP MAC address DIP switch GPIO and moved MS/TP configuration to AV objects. Added AV units property. Added some Uno R3 Digital Inputs and outputs mapped to some BV. Added AVR EEPROM from BDK port and mapped some non-volatile data including MAC address and max manager and baud rate, device ID and names and description and location.
2024-09-27 14:42:47 -05:00

187 lines
5.4 KiB
C

/**
* @brief This module manages the main C code for the BACnet demo
* @author Steve Karg <skarg@users.sourceforge.net>
* @date 2007
* @copyright SPDX-License-Identifier: MIT
*/
#include <stdbool.h>
#include <stdint.h>
#include "hardware.h"
#include "adc.h"
#include "nvdata.h"
#include "rs485.h"
#include "stack.h"
#include "bacnet/datalink/datalink.h"
#include "bacnet/npdu.h"
#include "bacnet/dcc.h"
#include "bacnet/basic/services.h"
#include "bacnet/basic/sys/mstimer.h"
#include "bacnet/basic/tsm/tsm.h"
#include "bacnet/iam.h"
#include "bacnet/basic/object/device.h"
#include "bacnet/basic/object/av.h"
#include "bacnet/basic/object/bv.h"
/* From the WhoIs hander - performed by the DLMSTP module */
extern bool Send_I_Am_Flag;
/* main loop task timer */
static struct mstimer Task_Timer;
/* uptime */
static uint32_t Uptime_Seconds;
/* dummy function - so we can use default demo handlers */
bool dcc_communication_enabled(void)
{
return true;
}
static void hardware_init(void)
{
/* Initialize the Clock Prescaler for ATmega48/88/168 */
/* The default CLKPSx bits are factory set to 0011 */
/* Enbable the Clock Prescaler */
CLKPR = _BV(CLKPCE);
/* CLKPS3 CLKPS2 CLKPS1 CLKPS0 Clock Division Factor
------ ------ ------ ------ ---------------------
0 0 0 0 1
0 0 0 1 2
0 0 1 0 4
0 0 1 1 8
0 1 0 0 16
0 1 0 1 32
0 1 1 0 64
0 1 1 1 128
1 0 0 0 256
1 x x x Reserved
*/
/* Set the CLKPS3..0 bits to Prescaler of 1 */
CLKPR = 0;
/* Initialize I/O ports */
/* For Port DDRx (Data Direction) Input=0, Output=1 */
/* For Port PORTx (Bit Value) TriState=0, High=1 */
DDRB = 0;
PORTB = 0;
DDRC = 0;
PORTC = 0;
DDRD = 0;
PORTD = 0;
/* Configure the watchdog timer - Disabled for testing */
BIT_CLEAR(MCUSR, WDRF);
WDTCSR = 0;
/* Configure Specialized Hardware */
RS485_Initialize();
mstimer_init();
adc_init();
/* Enable global interrupts */
__enable_interrupt();
}
/**
* @brief process some values once per second
*/
static void one_second_task(void)
{
BACNET_BINARY_PV value;
float hours;
/* LED toggling */
value = Binary_Value_Present_Value(99);
if (value == BINARY_ACTIVE) {
value = BINARY_INACTIVE;
} else {
value = BINARY_ACTIVE;
}
Binary_Value_Present_Value_Set(99, value);
/* uptime */
Uptime_Seconds += 1;
hours = (float)Uptime_Seconds / 3600.0f;
Analog_Value_Present_Value_Set(99, hours, 0);
}
/**
* Initialize the device's non-volatile data
*/
static void device_nvdata_init(void)
{
uint8_t value8;
uint16_t value16;
uint32_t value32;
const char *default_name = "AVR Device";
const char *default_description = "Description";
const char *default_location = "Location";
value16 = nvdata_unsigned16(NV_EEPROM_TYPE_0);
if (value16 != NV_EEPROM_TYPE_ID) {
/* set to defaults */
nvdata_unsigned16_set(NV_EEPROM_TYPE_0, NV_EEPROM_TYPE_ID);
nvdata_unsigned8_set(NV_EEPROM_VERSION, NV_EEPROM_VERSION_ID);
nvdata_unsigned8_set(NV_EEPROM_MSTP_MAC, 123);
nvdata_unsigned8_set(NV_EEPROM_MSTP_BAUD_K, 38);
nvdata_unsigned8_set(NV_EEPROM_MSTP_MAX_MASTER, 127);
nvdata_unsigned24_set(NV_EEPROM_DEVICE_0, 260123);
nvdata_name_set(
NV_EEPROM_DEVICE_NAME, CHARACTER_UTF8, default_name,
strlen(default_name));
nvdata_name_set(
NV_EEPROM_DEVICE_DESCRIPTION, CHARACTER_UTF8, default_description,
strlen(default_description));
nvdata_name_set(
NV_EEPROM_DEVICE_LOCATION, CHARACTER_UTF8, default_location,
strlen(default_location));
}
value8 = nvdata_unsigned8(NV_EEPROM_MSTP_MAC);
dlmstp_set_mac_address(value8);
value8 = nvdata_unsigned8(NV_EEPROM_MSTP_BAUD_K);
value32 = RS485_Baud_Rate_From_Kilo(value8);
RS485_Set_Baud_Rate(value32);
value8 = nvdata_unsigned8(NV_EEPROM_MSTP_MAX_MASTER);
if (value8 > 127) {
value8 = 127;
}
dlmstp_set_max_master(value8);
dlmstp_set_max_info_frames(1);
Send_I_Am_Flag = true;
}
/**
* Static receive buffer,
* initialized with zeros by the C Library Startup Code.
* Note: Added a little safety margin to the buffer,
* so that in the rare case, the message would be filled
* up to MAX_MPDU and some decoding functions would overrun,
* these decoding functions will just end up in a safe field
* of static zeros. */
static uint8_t PDUBuffer[MAX_MPDU + 16];
/**
* Main function
* @return 0, should never reach this
*/
int main(void)
{
uint16_t pdu_len = 0;
BACNET_ADDRESS src; /* source address */
hardware_init();
Analog_Value_Init();
Binary_Value_Init();
device_nvdata_init();
dlmstp_init(NULL);
mstimer_set(&Task_Timer, 1000);
for (;;) {
/* process */
if (mstimer_expired(&Task_Timer)) {
mstimer_reset(&Task_Timer);
one_second_task();
}
/* BACnet handling */
pdu_len = dlmstp_receive(&src, &PDUBuffer[0], MAX_MPDU, 0);
if (pdu_len) {
npdu_handler(&src, &PDUBuffer[0], pdu_len);
}
}
}