Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F85579283
arke.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Mon, Sep 30, 02:17
Size
8 KB
Mime Type
text/x-c
Expires
Wed, Oct 2, 02:17 (2 d)
Engine
blob
Format
Raw Data
Handle
21205206
Attached To
R7582 FORmicidae Tracker - Communication Protocol Implementations - libarke
arke.c
View Options
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <arke-avr.h>
#include <arke-avr/systime.h>
#include <yaacl.h>
#if defined(ARKE_MY_FW_TWEAK_VERSION)
#define VERSION_LENGTH 4
#elif defined(ARKE_MY_FW_PATCH_VERSION)
#define VERSION_LENGTH 3
#else
#define VERSION_LENGTH 2
#endif
#ifndef ARKE_MY_SIZE
#error "Please define ARKE_MY_SIZE"
#else
#define ARKE_RX_IDT(ID_) ( (ARKE_MESSAGE << 9) | (ARKE_MY_CLASS << 3) | (ID_))
#define ARKE_RX_IDT_MASK (ARKE_MESSAGE_TYPE_MASK | ((~(ARKE_MY_SIZE - 1) & 0x3f) << 3) | 0x07 )
#define ARKE_RX_BROAD_MASK (ARKE_MESSAGE_TYPE_MASK | ((~(ARKE_MY_SIZE - 1) & 0x3f) << 3))
#endif
typedef
enum
ArkeHeartbeatStatus_e
{
NO_HEARTBEAT
=
0
,
HEARTBEAT_ONCE
=
1
,
HEARTBEAT_REPEAT
=
2
}
ArkeHeartbeatStatus_e
;
#define ARKE_ERROR_FIFO_SIZE 16
#define ARKE_ERROR_FIFO_MASK 15
struct
ArkeErrorFIFO_t
{
ArkeError_t
data
[
ARKE_ERROR_FIFO_SIZE
];
uint8_t
size
,
head
,
tail
;
};
#define FIFO_INIT(f) do { \
(f).size = 0; \
(f).head = 0; \
(f).tail = 0; \
}while(0)
#define FIFO_FULL(f) ((f).size >= ARKE_ERROR_FIFO_SIZE)
#define FIFO_EMPTY(f) ((f).size == 0)
#define FIFO_HEAD(f) ((f).data[(f).head])
#define FIFO_TAIL(f) ((f).data[(f).tail])
#define FIFO_INCR_PTR(p) (p) = ((p) + 1) & ARKE_ERROR_FIFO_MASK
#define FIFO_INCREMENT_HEAD(f) do{ \
FIFO_INCR_PTR((f).head); \
(f).size -= 1; \
}while(0)
#define FIFO_INCREMENT_TAIL(f) do{ \
FIFO_INCR_PTR((f).tail); \
(f).size += 1; \
}while(0)
typedef
struct
ArkeData_t
{
//we limit ourselfs to 6 MOb
yaacl_txn_t
control
;
yaacl_txn_t
heartbeat
,
error
;
yaacl_txn_t
rx
,
broadcast
;
uint8_t
rxLength
;
uint8_t
*
rxBuffer
;
uint8_t
controlData
[
8
];
uint8_t
heartbeatData
[
VERSION_LENGTH
];
uint8_t
errorData
[
4
];
ArkeHeartbeatStatus_e
heartbeatStatus
;
ArkeSystime_t
heartbeatPeriod
;
ArkeSystime_t
lastHeartbeat
;
uint8_t
ID
;
struct
ArkeErrorFIFO_t
errors
;
}
ArkeData_t
;
#define arke_prepare_rx_txn(ID_) do { \
yaacl_make_std_idt(arke.rx.ID,ARKE_RX_IDT(ID_),0); \
yaacl_make_std_mask(arke.rx.mask,ARKE_RX_IDT_MASK,0,1); \
arke.rx.length = arke.rxLength; \
arke.rx.data = arke.rxBuffer; \
}while(0);
#define arke_prepare_broadcast_txn(ID_) do { \
yaacl_make_std_idt(arke.broadcast.ID,ARKE_RX_IDT(ID_),0); \
yaacl_make_std_mask(arke.broadcast.mask,ARKE_RX_BROAD_MASK,0,1); \
arke.broadcast.length = arke.rxLength; \
arke.broadcast.data = arke.rxBuffer; \
}while(0);
ArkeData_t
arke
;
uint8_t
EEMEM
arkeID
=
1
;
void
InitArke
(
uint8_t
*
rxBuffer
,
uint8_t
length
)
{
uint8_t
sreg
=
SREG
;
cli
();
arke
.
ID
=
eeprom_read_byte
(
&
arkeID
);
if
(
arke
.
ID
==
0
||
arke
.
ID
>
7
)
{
arke
.
ID
=
1
;
}
SREG
=
sreg
;
arke
.
heartbeatData
[
0
]
=
ARKE_MY_FW_MAJOR_VERSION
;
arke
.
heartbeatData
[
1
]
=
ARKE_MY_FW_MINOR_VERSION
;
#if VERSION_LENGTH > 2
arke
.
heartbeatData
[
2
]
=
ARKE_MY_FW_PATCH_VERSION
;
#endif
#if VERSION_LENGTH > 3
arke
.
heartbeatData
[
3
]
=
ARKE_MY_FW_TWEAK_VERSION
;
#endif
arke
.
heartbeatStatus
=
NO_HEARTBEAT
;
arke
.
heartbeatPeriod
=
0
;
ArkeInitSystime
();
yaacl_config_t
config
;
config
.
baudrate
=
YAACL_BR_250
;
yaacl_init
(
&
config
);
yaacl_init_txn
(
&
(
arke
.
control
));
yaacl_init_txn
(
&
(
arke
.
error
));
yaacl_init_txn
(
&
(
arke
.
heartbeat
));
yaacl_init_txn
(
&
(
arke
.
rx
));
//reserve immediatly the highest priority Mob for Network Control Handling
yaacl_make_std_idt
(
arke
.
control
.
ID
,
0
,
0
);
yaacl_make_std_mask
(
arke
.
control
.
mask
,
ARKE_MESSAGE_TYPE_MASK
,
1
,
1
);
arke
.
control
.
length
=
8
;
arke
.
control
.
data
=
&
(
arke
.
controlData
[
0
]);
arke
.
error
.
ID
=
arke
.
ID
;
arke
.
error
.
length
=
4
;
arke
.
error
.
data
=
&
(
arke
.
errorData
[
0
]);
arke
.
error
.
data
[
0
]
=
ARKE_MY_CLASS
;
arke
.
error
.
data
[
1
]
=
arke
.
ID
;
arke
.
error
.
data
[
2
]
=
0
;
arke
.
error
.
data
[
3
]
=
0
;
arke
.
heartbeat
.
ID
=
(
ARKE_HEARTBEAT
<<
9
)
|
(
ARKE_MY_CLASS
<<
3
)
|
arke
.
ID
;
arke
.
heartbeat
.
data
=
&
(
arke
.
heartbeatData
[
0
]);
arke
.
rxLength
=
length
;
arke
.
rxBuffer
=
rxBuffer
;
arke_prepare_rx_txn
(
arke
.
ID
);
arke_prepare_broadcast_txn
(
arke
.
ID
);
yaacl_listen
(
&
arke
.
control
);
yaacl_listen
(
&
arke
.
broadcast
);
yaacl_listen
(
&
arke
.
rx
);
FIFO_INIT
(
arke
.
errors
);
}
void
ProcessControl
()
{
uint8_t
command
=
arke
.
control
.
ID
&
ARKE_SUBID_MASK
;
uint8_t
dataLength
=
arke
.
control
.
length
;
// we are forbidden to access any yaacl function here
if
(
command
==
ARKE_RESET_REQUEST
&&
dataLength
==
1
)
{
uint8_t
targetID
=
arke
.
controlData
[
0
];
if
(
targetID
==
0
||
targetID
==
arke
.
ID
)
{
ArkeSoftwareReset
();
}
return
;
}
if
(
command
==
ARKE_HEARTBEAT_REQUEST
)
{
if
(
dataLength
==
0
||
(
dataLength
==
2
&&
arke
.
controlData
[
0
]
==
0
&&
arke
.
controlData
[
1
]
==
0
)
)
{
// single heartbeat request
arke
.
heartbeatPeriod
=
0
;
arke
.
lastHeartbeat
=
ArkeGetSystime
();
arke
.
heartbeatStatus
=
HEARTBEAT_ONCE
;
}
else
if
(
dataLength
==
2
)
{
*
(((
uint8_t
*
)(
&
arke
.
heartbeatPeriod
))
+
0
)
=
arke
.
controlData
[
0
];
*
(((
uint8_t
*
)(
&
arke
.
heartbeatPeriod
))
+
1
)
=
arke
.
controlData
[
1
];
arke
.
lastHeartbeat
=
ArkeGetSystime
();
arke
.
heartbeatStatus
=
HEARTBEAT_REPEAT
;
}
return
;
}
if
(
command
==
ARKE_ID_CHANGE_REQUEST
&&
dataLength
==
2
&&
arke
.
controlData
[
0
]
==
arke
.
ID
&&
arke
.
controlData
[
1
]
>
0
&&
arke
.
controlData
[
1
]
<
8
)
{
arke
.
ID
=
arke
.
controlData
[
1
];
uint8_t
sreg
=
SREG
;
cli
();
eeprom_update_byte
(
&
arkeID
,
arke
.
ID
);
SREG
=
sreg
;
// needed, but normally you won't change ID on the fly.
ArkeSoftwareReset
();
return
;
}
}
yaacl_idt_t
ArkeProcessNodeMessage
(
uint8_t
*
length
)
{
yaacl_txn_status_e
s
=
yaacl_txn_status
(
&
arke
.
rx
);
yaacl_idt_t
ret
=
ARKE_NO_MESSAGE
;
if
(
s
==
YAACL_TXN_COMPLETED
)
{
*
length
=
arke
.
rx
.
length
;
ret
=
arke
.
rx
.
ID
;
}
if
(
s
!=
YAACL_TXN_PENDING
)
{
arke_prepare_rx_txn
(
arke
.
ID
);
yaacl_listen
(
&
arke
.
rx
);
}
if
(
ret
!=
ARKE_NO_MESSAGE
)
{
return
ret
;
}
s
=
yaacl_txn_status
(
&
arke
.
broadcast
);
if
(
s
==
YAACL_TXN_COMPLETED
)
{
*
length
=
arke
.
broadcast
.
length
;
ret
=
arke
.
broadcast
.
ID
;
}
if
(
s
!=
YAACL_TXN_PENDING
)
{
arke_prepare_broadcast_txn
(
arke
.
ID
);
yaacl_listen
(
&
arke
.
broadcast
);
}
return
ret
;
}
void
arkeSendErrors
()
{
if
(
FIFO_EMPTY
(
arke
.
errors
)
||
yaacl_txn_status
(
&
(
arke
.
error
))
!=
YAACL_TXN_UNSUBMITTED
)
{
return
;
}
ArkeError_t
e
=
FIFO_HEAD
(
arke
.
errors
);
arke
.
errorData
[
2
]
=
e
&
0x00ff
;
arke
.
errorData
[
3
]
=
(
e
&
0xff00
)
>>
8
;
yaacl_error_e
err
=
yaacl_send
(
&
(
arke
.
error
));
if
(
err
==
YAACL_ERR_MOB_OVERFLOW
)
{
return
;
}
FIFO_INCREMENT_HEAD
(
arke
.
errors
);
}
yaacl_idt_t
ArkeProcess
(
uint8_t
*
length
)
{
yaacl_txn_status_e
s
=
yaacl_txn_status
(
&
(
arke
.
control
));
if
(
s
==
YAACL_TXN_COMPLETED
)
{
// ID and data will not change unless yaacl_txn_status is
// called again.
uint8_t
targetID
=
(
arke
.
control
.
ID
&
ARKE_NODE_CLASS_MASK
)
>>
3
;
if
(
targetID
==
0x00
||
targetID
==
ARKE_MY_CLASS
)
{
ProcessControl
();
}
}
if
(
s
!=
YAACL_TXN_PENDING
)
{
// we received or had an error, we re-listen
arke
.
control
.
length
=
8
;
yaacl_listen
(
&
(
arke
.
control
));
}
yaacl_idt_t
toReturn
=
ArkeProcessNodeMessage
(
length
);
arkeSendErrors
();
// heartbeat
if
(
arke
.
heartbeatStatus
==
NO_HEARTBEAT
||
yaacl_txn_status
(
&
(
arke
.
heartbeat
))
!=
YAACL_TXN_UNSUBMITTED
)
{
//we are sending or just have sent an heartbeat, or we do not
//need a periodic heartbeat
return
toReturn
;
}
ArkeSystime_t
now
=
ArkeGetSystime
();
if
(
(
now
-
arke
.
lastHeartbeat
)
<
arke
.
heartbeatPeriod
)
{
// wait before sending a new heartbeat
return
toReturn
;
}
arke
.
heartbeat
.
length
=
(
arke
.
heartbeatStatus
==
HEARTBEAT_ONCE
)
?
VERSION_LENGTH
:
0
;
yaacl_error_e
err
=
yaacl_send
(
&
(
arke
.
heartbeat
));
if
(
err
==
YAACL_ERR_MOB_OVERFLOW
)
{
// no free Mob, no worries, we fo it later.
return
toReturn
;
}
//heartbeat succesfully submitted
if
(
arke
.
heartbeatStatus
==
HEARTBEAT_ONCE
)
{
arke
.
heartbeatStatus
=
NO_HEARTBEAT
;
}
else
{
arke
.
lastHeartbeat
=
now
;
}
return
toReturn
;
}
#define implement_sender_function(name) \
ARKE_DECLARE_SENDER_FUNCTION(name) { \
txn->ID = arke.ID \
| ( Arke ## name ## ClassValue << 3) \
| ( (emergency ? ARKE_HIGH_PRIORITY_MESSAGE : ARKE_MESSAGE) << 9) ; \
txn->length = sizeof(Arke ## name); \
txn->data = (uint8_t*)data; \
return yaacl_send(txn); \
}
implement_sender_function
(
ZeusSetPoint
)
implement_sender_function
(
ZeusReport
)
implement_sender_function
(
ZeusStatus
)
implement_sender_function
(
ZeusConfig
)
implement_sender_function
(
ZeusControlPoint
)
implement_sender_function
(
ZeusDeltaTemperature
)
implement_sender_function
(
HeliosSetPoint
)
implement_sender_function
(
CelaenoSetPoint
)
implement_sender_function
(
CelaenoStatus
)
implement_sender_function
(
CelaenoConfig
)
void
ArkeReportError
(
ArkeError_t
error
)
{
if
(
FIFO_FULL
(
arke
.
errors
)
)
{
return
;
}
FIFO_TAIL
(
arke
.
errors
)
=
error
;
FIFO_INCREMENT_TAIL
(
arke
.
errors
);
}
Event Timeline
Log In to Comment