Commit e802ca40 authored by Bc. Petr Elexa's avatar Bc. Petr Elexa

panel: update comments

parent 0dd54232
// ACS CAN protocol
//
// Contains defines and data types for the protocol
//
/**
* @file
* @brief ACS CAN protocol
*
* Contains defines and data types for the protocol.
* ACS protocol uses messages with extended ID from CAN 2.0B specification.
*
* @author Petr Elexa
* @see LICENSE
*
*/
#ifndef ACS_CAN_PROTOCOL_H_
#define ACS_CAN_PROTOCOL_H_
// Used Message object numbers
// Used Message object numbers.
#define ACS_MSGOBJ_SEND_DOOR_A 0
#define ACS_MSGOBJ_SEND_DOOR_B 1
#define ACS_MSGOBJ_RECV_DOOR_A 2
#define ACS_MSGOBJ_RECV_DOOR_B 3
#define ACS_MSGOBJ_RECV_BCAST 4
// HEAD partitions sizes
// Message head partition sizes (29b total).
#define ACS_PRIO_BITS 3
#define ACS_FC_BITS 6
#define ACS_ADDR_BITS 10
// Address space
// Address space.
#define ACS_BROADCAST_ADDR ((1 << ACS_ADDR_BITS) - 1)
#define ACS_RESERVED_ADDR 0
#define ACS_MSTR_FIRST_ADDR 1
......@@ -26,22 +33,19 @@
#define ACS_PNL_FIRST_ADDR 4
#define ACS_PNL_LAST_ADDR (ACS_BROADCAST_ADDR - 1)
// message head offsets
// Message head offsets.
#define ACS_SRC_ADDR_OFFSET 0
#define ACS_DST_ADDR_OFFSET (ACS_SRC_ADDR_OFFSET + ACS_ADDR_BITS)
#define ACS_FC_OFFSET (ACS_DST_ADDR_OFFSET + ACS_ADDR_BITS)
#define ACS_PRIO_OFFSET (ACS_FC_OFFSET + ACS_FC_BITS)
// message head masks
// Message head masks.
#define ACS_SRC_ADDR_MASK (((1 << ACS_ADDR_BITS) - 1) << ACS_SRC_ADDR_OFFSET)
#define ACS_DST_ADDR_MASK (((1 << ACS_ADDR_BITS) - 1) << ACS_DST_ADDR_OFFSET)
#define ACS_FC_MASK (((1 << ACS_FC_BITS) - 1) << ACS_FC_OFFSET)
#define ACS_PRIO_MASK (((1 << ACS_PRIO_BITS) - 1) << ACS_PRIO_OFFSET)
#define ACS_MAX_PRIO 0
#define ACS_LOW_PRIO ((1 << ACS_PRIO_BITS) - 1)
// ACS protocol function codes
// Function codes used in ACS protocol.
#define FC_RESERVED 0x0
#define FC_USER_AUTH_REQ 0x1 // S -> M
#define FC_USER_NOT_AUTH_RESP 0x2 // M -> S
......@@ -50,7 +54,11 @@
#define FC_DOOR_STATUS 0x5 // S -> M
#define FC_ALIVE 0x6 // M -> S
// priorities for each function code (0-7)
// Priority range.
#define ACS_MAX_PRIO 0
#define ACS_LOW_PRIO ((1 << ACS_PRIO_BITS) - 1)
// Priorities for each function code (ACS_MAX_PRIO to ACS_LOW_PRIO).
#define PRIO_RESERVED 0x0
#define PRIO_USER_AUTH_REQ 0x2
#define PRIO_USER_AUTH_RESP_FAIL 0x2
......@@ -59,23 +67,26 @@
#define PRIO_DOOR_STATUS 0x4
#define PRIO_ALIVE 0x1
// Data for FC_DOOR_CTRL
// Data for FC_DOOR_CTRL.
#define DATA_DOOR_CTRL_REMOTE_UNLCK 0x01
#define DATA_DOOR_CTRL_CLR_CACHE 0x02
// Data for FC_DOOR_STATUS
// Data for FC_DOOR_STATUS.
#define DATA_DOOR_STATUS_CLOSED 0x01
#define DATA_DOOR_STATUS_OPEN 0x02
// Setting for master communication status
// Setting for master communication status.
#define ACS_MASTER_ALIVE_PERIOD_MS 5000
#define ACS_MASTER_ALIVE_TIMEOUT_MS 10000
// Data type definitions
/*
* Data types definitions.
*/
#pragma pack(push,1)
// Structure describing the message head (CAN ID).
typedef union
{
struct
......@@ -89,16 +100,19 @@ typedef union
uint32_t scalar;
} acs_msg_head_t;
// Structure of data sent with FC_USER_AUTH_REQ.
typedef struct
{
uint32_t user_id;
} acs_msg_data_auth_req_t;
// Structure of data sent with FC_USER_AUTH_RESP and FC_USER_NOT_AUTH_RESP.
typedef struct
{
uint32_t user_id;
} acs_msg_data_auth_resp_t;
// Structure of data sent with FC_DOOR_CTRL.
typedef struct
{
uint8_t ctrl_command;
......
/*
Main startup sequence
*/
/**
* @file
* @brief Main entry point
*
* Contains start-up sequence.
*
* @author Petr Elexa
* @see LICENSE
*
*/
#include "can/can_term_driver.h"
#include "terminal.h"
......@@ -27,7 +34,7 @@
* Private functions
****************************************************************************/
static void check_system_stack_size(void)
static void _check_system_stack_size(void)
{
extern unsigned long _vStackTop[], _pvHeapStart[];
unsigned long ulInterruptStackSize;
......@@ -54,6 +61,7 @@ int main(void)
{
__disable_irq();
// Init brown-out detection.
BOD_Init();
// Set up and initialize all required blocks and
......@@ -70,13 +78,13 @@ int main(void)
WDT_Feed();
terminal_init();
terminal_init(); // Terminal init requires enabled interrupts.
WDT_Feed();
check_system_stack_size();
_check_system_stack_size();
/* Start the kernel. From here on, only tasks and interrupts will run. */
// Start the kernel. From here on, only tasks and interrupts will run.
vTaskStartScheduler();
return 1;
......
/*
* Similar to Set Associative Cache.
* Divide into sets by key. Each set is a sorted array.
/**
* @file
* @brief Statically allocated cache for user IDs.
*
* It is similar to Set Associative Cache.
* Place key and value into sets by key hash. Each set is a sorted array.
*
* @author Petr Elexa
* @see LICENSE
*
*/
......@@ -9,12 +15,17 @@
#if CACHING_ENABLED
/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/
typedef struct
{
cache_item_t * const ptr_items;
int length;
} cache_set_t;
// Allocate cache in memory.
static cache_item_t _cache_set_0[STATIC_CACHE_SET_CAP];
static cache_item_t _cache_set_1[STATIC_CACHE_SET_CAP];
static cache_item_t _cache_set_2[STATIC_CACHE_SET_CAP];
......@@ -28,6 +39,11 @@ static cache_set_t _cache_sets[STATIC_CACHE_SETS]
{_cache_set_3, 0}
};
/*****************************************************************************
* Private functions
****************************************************************************/
// Standard implementation of binary search.
static bool _binary_search(const cache_set_t * ptr_set, const cache_item_t kv, int * ptr_idx)
{
int down = 0;
......@@ -42,20 +58,24 @@ static bool _binary_search(const cache_set_t * ptr_set, const cache_item_t kv, i
else
{
*ptr_idx = mid;
return true; // found
return true; // Found.
}
}
*ptr_idx = down;
return false; //not found
return false; // Not found.
}
// Retrieve cache set the key should be in. Decide from first two bits.
// O(1)
static inline cache_set_t * _get_cache_set(const cache_item_t kv)
{
return &_cache_sets[(kv.key & 0x3)];
}
// O(log (STATIC_CACHE_CAPACITY / STATIC_CACHE_SETS))
/*****************************************************************************
* Public functions
****************************************************************************/
bool static_cache_get(cache_item_t * ptr_kv)
{
const cache_set_t * ptr_set = _get_cache_set(*ptr_kv);
......@@ -63,18 +83,17 @@ bool static_cache_get(cache_item_t * ptr_kv)
int idx = 0;
if (_binary_search(ptr_set, *ptr_kv, &idx))
{
//found
// Found.
*ptr_kv = ptr_set->ptr_items[idx];
return true;
}
else
{
//not found
// Not found.
return false;
}
}
// O(log (STATIC_CACHE_CAPACITY / 4) + 2*(STATIC_CACHE_CAPACITY / 4))
void static_cache_insert(const cache_item_t kv)
{
cache_set_t * ptr_set = _get_cache_set(kv);
......@@ -82,18 +101,18 @@ void static_cache_insert(const cache_item_t kv)
int idx = 0;
if (_binary_search(ptr_set, kv, &idx))
{
ptr_set->ptr_items[idx] = kv; // update existing item
ptr_set->ptr_items[idx] = kv; // Update existing item.
}
else
{
if ( 1 + ptr_set->length >= STATIC_CACHE_SET_CAP)
{
// cache set full - replace existing
// Cache set full - replace existing.
ptr_set->ptr_items[idx] = kv;
}
else
{
// move items and place new one
// Move items and place new one.
for (int i = ptr_set->length - 1; i >= idx; --i)
{
ptr_set->ptr_items[i + 1] = ptr_set->ptr_items[i];
......@@ -104,7 +123,6 @@ void static_cache_insert(const cache_item_t kv)
}
}
// O(log (STATIC_CACHE_CAPACITY / 4) + 2*(STATIC_CACHE_CAPACITY / 4))
void static_cache_erase(const cache_item_t kv)
{
cache_set_t * ptr_set = _get_cache_set(kv);
......@@ -112,7 +130,7 @@ void static_cache_erase(const cache_item_t kv)
int idx;
if (_binary_search(ptr_set, kv, &idx))
{
// found delete and move remaining
// Key was found - delete and fill the empty position.
for (int i = idx; i < ptr_set->length - 1; ++i)
{
ptr_set->ptr_items[i] = ptr_set->ptr_items[i + 1];
......
/**
* @file
* @brief Statically allocated cache for user IDs.
*
* It is similar to Set Associative Cache.
* Divide key and value into sets by key hash. Each set is a sorted array.
*
* The key in cache can be up to 30 bits in size.
*
* @author Petr Elexa
* @see LICENSE
*
*/
#ifndef STATIC_CACHE_H_
#define STATIC_CACHE_H_
......@@ -5,13 +19,18 @@
#include <stdbool.h>
#include "terminal_config.h"
#define STATIC_CACHE_SETS 4
#define STATIC_CACHE_SET_CAP 128
/** Configuration of the static cache. */
#define STATIC_CACHE_SETS 4
#define STATIC_CACHE_SET_CAP 128
#define STATIC_CACHE_CAPACITY (STATIC_CACHE_SET_CAP * STATIC_CACHE_SETS)
// cache item type
/*****************************************************************************
* Public types/enumerations/variables
****************************************************************************/
#pragma pack(push,1)
typedef union
{
struct
......@@ -20,14 +39,68 @@ typedef union
uint32_t key : 30;
};
uint32_t scalar;
} cache_item_t;
} cache_item_t; ///< Generic type of the item used in cache.
#pragma pack(pop)
/*****************************************************************************
* Public functions
****************************************************************************/
/**
* @brief Retrieve item from the cache.
*
* Complexity is O(log(STATIC_CACHE_SET_CAP)).
*
* @param ptr_kv ... Pointer to cache_item_t containing key. The value will be filled in
* if key is found.
*
* @return true if key is found.
*/
bool static_cache_get(cache_item_t * ptr_kv);
/**
* @brief Insert item to the cache.
*
* Will overwrite items already in cache if the cache is full. Will also update item
* with same key.
*
* Complexity is O(log(STATIC_CACHE_SET_CAP) + 2*(STATIC_CACHE_SET_CAP)).
*
* @param kv ... Key and value to be inserted.
*/
void static_cache_insert(const cache_item_t kv);
/**
* @brief Erase item from the cache.
*
* Complexity is O(log(STATIC_CACHE_SET_CAP) + 2*(STATIC_CACHE_SET_CAP)).
*
* @param kv ... Key containing key to be erased. The item will erased
* if key is found.
*/
void static_cache_erase(const cache_item_t kv);
/**
* @brief Clear all data in the cache.
*
* Resets all data in cache to 0s.
* Complexity is O(STATIC_CACHE_CAPACITY).
*
*/
void static_cache_reset(void);
/**
* @brief Create cache item from key and value parameters.
*
*
* @param key ... Key for the value.
* @param value ... Value for key to use.
*
* @return Cache item structure.
*/
cache_item_t static_cache_convert(uint32_t key, uint32_t value);
#endif /* STATIC_CACHE_H_ */
......@@ -19,7 +19,13 @@
#include <stdio.h>
#include <string.h>
#define USER_REQUEST_WAIT_MS 1000
/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/
// How long to wait for user request.
// This also controls intensity of door status messages.
static const uint16_t USER_REQUEST_WAIT_MS = 1500;
// Cache entry type mapping to our type.
typedef cache_item_t term_cache_item_t; // 4 bytes
......@@ -46,7 +52,11 @@ static TimerHandle_t _act_timer = NULL;
static const uint32_t _act_timer_id = TERMINAL_TIMER_ID;
// Last door open(true) / close(false) status
static bool last_door_state[ACS_READER_COUNT] = {false, false};
static bool _last_door_state[ACS_READER_COUNT] = {false, false};
/*****************************************************************************
* Private functions
****************************************************************************/
// Map reader index to correct cache value.
static inline uint8_t map_reader_idx_to_cache(uint8_t reader_idx)
......@@ -54,13 +64,13 @@ static inline uint8_t map_reader_idx_to_cache(uint8_t reader_idx)
return (reader_idx == ACS_READER_A_IDX ? cache_reader_A : cache_reader_B);
}
static inline void terminal_user_authorized(uint8_t reader_idx)
static inline void _terminal_user_authorized(uint8_t reader_idx)
{
DEBUGSTR("auth OK\n");
reader_unlock(reader_idx, BEEP_ON_SUCCESS, OK_LED_ON_SUCCESS);
}
static inline void terminal_user_not_authorized(uint8_t reader_idx)
static inline void __terminal_user_not_authorized(uint8_t reader_idx)
{
(void)reader_idx;
DEBUGSTR("auth FAIL\n");
......@@ -88,6 +98,10 @@ static void _timer_callback(TimerHandle_t pxTimer)
}
}
/*****************************************************************************
* Public functions
****************************************************************************/
void term_can_error(uint32_t error_info)
{
(void)error_info;
......@@ -152,7 +166,7 @@ void term_can_recv(uint8_t msg_obj_num)
// Continue deducing action and execute it.
if (head.fc == FC_USER_AUTH_RESP)
{
terminal_user_authorized(reader_idx);
_terminal_user_authorized(reader_idx);
#if CACHING_ENABLED
uint32_t user_id;
......@@ -166,7 +180,7 @@ void term_can_recv(uint8_t msg_obj_num)
}
else if (head.fc == FC_USER_NOT_AUTH_RESP)
{
terminal_user_not_authorized(reader_idx);
__terminal_user_not_authorized(reader_idx);
#if CACHING_ENABLED
uint32_t user_id;
......@@ -273,7 +287,7 @@ static void terminal_user_identified(uint32_t user_id, uint8_t reader_idx)
{
if (map_reader_idx_to_cache(reader_idx) & user.value)
{
terminal_user_authorized(reader_idx);
_terminal_user_authorized(reader_idx);
}
}
else
......@@ -285,17 +299,19 @@ static void terminal_user_identified(uint32_t user_id, uint8_t reader_idx)
}
}
// Main terminal processing task.
// Main loop in terminal processing task.
//
// Waked only when request is in the reader buffer.
// Waked only when request is in the reader buffer or after timeout.
static void terminal_task(void *pvParameters)
{
(void)pvParameters;
// start timer for detecting master timeout
configASSERT(xTimerStart(_act_timer, 0));
while (true)
{
// Get pending user request
uint32_t user_id;
uint8_t reader_idx = reader_get_request_from_buffer(&user_id, USER_REQUEST_WAIT_MS);
if (reader_idx < ACS_READER_COUNT)
......@@ -306,11 +322,11 @@ static void terminal_task(void *pvParameters)
// Check if door open/close state changed
for (size_t idx = 0; idx < ACS_READER_COUNT; ++idx)
{
if (reader_is_door_open(idx) != last_door_state[idx])
if (reader_is_door_open(idx) != _last_door_state[idx])
{
DEBUGSTR("new door state\n");
last_door_state[idx] = !last_door_state[idx];
terminal_send_door_status(idx, last_door_state[idx]);
_last_door_state[idx] = !_last_door_state[idx];
terminal_send_door_status(idx, _last_door_state[idx]);
}
}
}
......
/*
* terminal_config.c
/**
* @file
* @brief Configuration of hardware and software.
*
* @author Petr Elexa
* @see LICENSE
*
* Author: Petr
*/
#include "terminal_config.h"
#include "storage.h"
#include "acs_can_protocol.h"
// Network address mask.
#define ACS_ADDR_BIT_MASK ((1 << ACS_ADDR_BITS) - 1)
// door addresses in ACS
// Door addresses in ACS.
uint16_t _READER_A_ADDR = 0x4; // even
uint16_t _READER_B_ADDR = 0x5; // odd
inline uint16_t get_reader_a_addr(void)
{
return _READER_A_ADDR;
......@@ -49,19 +54,19 @@ static bool _save_acs_addrs_from_ext_stor(void)
return ret_val;
}
void set_reader_addr(uint16_t first_acs_addr)
void set_reader_addr(uint16_t acs_addr)
{
first_acs_addr &= ACS_ADDR_BIT_MASK;
acs_addr &= ACS_ADDR_BIT_MASK;
if (first_acs_addr & 0x1) // even address
if (acs_addr & 0x1) // even address
{
_READER_B_ADDR = first_acs_addr;
_READER_A_ADDR = first_acs_addr - 1;
_READER_B_ADDR = acs_addr;
_READER_A_ADDR = acs_addr - 1;
}
else // odd address
{
_READER_A_ADDR = first_acs_addr;
_READER_B_ADDR = first_acs_addr + 1;
_READER_A_ADDR = acs_addr;
_READER_B_ADDR = acs_addr + 1;
}
}
......
/*
* terminal_config.h
/**
* @file
* @brief Terminal client configuration (hardware and software).
* *
* @author Petr Elexa
* @see LICENSE
*
* Created on: 24. 8. 2018
* Author: Petr
*/
#ifndef BSP_BOARD_CONFIG_H_
#define BSP_BOARD_CONFIG_H_
#ifndef TERM_CONFIG_H_
#define TERM_CONFIG_H_
#include <stdint.h>
#include <stdbool.h>
#define DEVEL_BOARD
//-------------------------------------------------------------
// General settings.
//-------------------------------------------------------------
// General settings
#define DEVEL_BOARD
// Enable write of ACS address to external storage on startup.
#define ENABLE_LOCAL_ACS_ADDR_WRITE 0
// enable caching for operation when communication is lost
// cache expiration is to be handled by master
// Enable caching for operation when communication is lost.
// Cache expiration is to be handled by master (Not implemented).
#define CACHING_ENABLED 0
// CAN bus speed b/s
// CAN bus speed b/s - affects maximum data cable length.
// Suggested option for common use are 100kbit/s and 125kbit/s.
#define CAN_BAUD_RATE 125000
// Setting for I2C external storage for door adresses
// (EEPROM, IO EXPANDER or device with same access).
#define STORE_I2C_BUS_FREQ 400000 // 100kHz or 400kHz
#define STORE_I2C_SLAVE_ADDR 0x50 // 7bit address
// Internal index of card readers (can be swapped).
#define ACS_READER_A_IDX 0
#define ACS_READER_B_IDX 1
// Number of card readers present 1 or 2.
#define ACS_READER_COUNT 2
#define BEEP_ON_SUCCESS false
#define OK_LED_ON_SUCCESS true
// Door sensor types (reed switch).
#define SENSOR_IS_NO 0 // Normally open (Form A).
#define SENSOR_IS_NC 1 // Normally closed (Form B).
// If DOOR_SENSOR_TYPE is defined enables door sensor.
#define DOOR_SENSOR_TYPE SENSOR_IS_NO
// Communication status led.
#define ACS_COMM_STATUS_LED_PORT 0
#define ACS_COMM_STATUS_LED_PIN 6
//-------------------------------------------------------------
// Global UID from vendor (from chip).
//-------------------------------------------------------------
// global UID from vendor (from chip)
#define IAP_READ_UID 58
extern unsigned int TERMINAL_UID[5]; // 0 - status code, 1 - least significant word
//-------------------------------------------------------------
// Door addresses in a network for ACS system
// Door addresses in a network for ACS system.
//-------------------------------------------------------------
//
// Read from external storage on startup
// Designed to be even (address A) and odd (address B)
// Always true: ADDR_B = ADDR_A + 1
// Address getters
/**
* @brief Get network address of door A.
*
*/
extern uint16_t get_reader_a_addr(void);
/**
* @brief Get network address of door B.
*
*/
extern uint16_t get_reader_b_addr(void);
// Address setter
void set_reader_addr(const uint16_t first_acs_addr);
/**
* @brief Address setter.
*
* @param acs_addr ... ACS network address (odd or even).
*/
void set_reader_addr(const uint16_t acs_addr);
// Expected organization in external address space:
// | 0x00 | A_ADDR [7:0]
......@@ -50,35 +95,7 @@ void set_reader_addr(const uint16_t first_acs_addr);
// The address actually uses less then 16 bits. See address bit width in ACS protocol.
#define PTR_READER_FIRST_ADDR 0x0 // pointer to external memory
// Setting for I2C external storage for door adresses
// (EEPROM, IO EXPANDER or device with same access)
#define STORE_I2C_BUS_FREQ 400000 // 100kHz or 400kHz
#define STORE_I2C_SLAVE_ADDR 0x50 // 7bit address
//-------------------------------------------------------------
// internal number of card readers
#define ACS_READER_A_IDX 0
#define ACS_READER_B_IDX 1
// card reader count 1/2
#define ACS_READER_COUNT 2
#define BEEP_ON_SUCCESS false
#define OK_LED_ON_SUCCESS true
// communication status led
#define ACS_COMM_STATUS_LED_PORT 0
#define ACS_COMM_STATUS_LED_PIN 6
// Door sensor types (reed switch).
#define SENSOR_IS_NO 0 // Normally open (Form A).
#define SENSOR_IS_NC 1 // Normally closed (Form B).
// If DOOR_SENSOR_TYPE is defined enables door sensor
#define DOOR_SENSOR_TYPE SENSOR_IS_NO
#define STORE_DEV_BUSY_FOR 50 // Number of read commands to try before EEPROM timeout
//---------------------------------------------------------------------------------------------------------------------
// Settings for RFID reader A
......@@ -126,8 +143,10 @@ void set_reader_addr(const uint16_t first_acs_addr);
#define ACS_READER_B_OPEN_TIME_MS 8000
#define ACS_READER_B_OK_GLED_TIME_MS 4000
//---------------------------------------------------------------------------------------------------------------------
// Internal setting
//---------------------------------------------------------------------------------------------------------------------
// if following is changed it will need code modification
#define WEIGAND_DEVICE_LIMIT 4
......@@ -139,23 +158,30 @@ void set_reader_addr(const uint16_t first_acs_addr);
#error "reader max count limit"
#endif
//---------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------
#define HW_WATCHDOG_TIMEOUT 1 // in seconds
//---------------------------------------------------------------------------------------------------------------------
// IO
//---------------------------------------------------------------------------------------------------------------------
#define LOG_HIGH 1
#define LOG_LOW 0
//---------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------
// Initialize configuration
// @return true if succeeded
/**
*
* @brief Initialize configuration for terminal.
*
* Reads address from storage.
* @return true if succeeded
*/
bool terminal_config_init(void);
//---------------------------------------------------------------------------------------------------------------------