Skip to content

Commit

Permalink
Significant rewrite. Switch from struct to int64. Add RTC sync suppor…
Browse files Browse the repository at this point in the history
…t. Untested.
  • Loading branch information
chintal committed Oct 3, 2024
1 parent e532964 commit 067f21b
Show file tree
Hide file tree
Showing 10 changed files with 376 additions and 227 deletions.
1 change: 1 addition & 0 deletions .piopm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"type": "library", "name": "ebs-time", "version": "9.9.9", "spec": {"owner": "chintal", "id": 17237, "name": "ebs-time", "requirements": null, "uri": null}}
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ebs-time",
"version": "0.1.1",
"version": "0.2.1",
"description": "Time keeping and manipulation functions for embedded systems",
"keywords": "ebs",
"repository": {
Expand Down
24 changes: 24 additions & 0 deletions src/time/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,30 @@
#define DESCRIPTOR_TAG_TIME_EPOCH 0x02
#endif

#if defined EBS_TIME_ENABLE_SYNC
#define TIME_ENABLE_SYNC EBS_TIME_ENABLE_SYNC
#elif defined APP_ENABLE_TIME_SYNC
#define TIME_ENABLE_SYNC APP_ENABLE_TIME_SYNC
#else
#define TIME_ENABLE_SYNC 0
#endif

#if defined APP_ENABLE_RTC
#define TIME_ENABLE_SYNC_RTC APP_ENABLE_RTC
#else
#define TIME_ENABLE_SYNC_RTC 0
#endif


#if defined EBS_TIME_ENABLE_CRON
#define TIME_ENABLE_CRON EBS_TIME_ENABLE_CRON
#elif defined APP_ENABLE_TIME_CRON
#define TIME_ENABLE_CRON APP_ENABLE_TIME_CRON
#else
#define TIME_ENABLE_CRON 0
#endif


/**@}*/


Expand Down
8 changes: 4 additions & 4 deletions src/time/cron.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ void tm_cron_clear_job(cron_job_t * job_p){
job_p->nextjob = NULL;
job_p->prevjob = NULL;
job_p->tafter_p = NULL;
job_p->texec.seconds = 0;
job_p->texec.frac = 0;
job_p->texec = 0;
job_p->active = 0;
}

Expand All @@ -57,8 +56,7 @@ void tm_cron_create_job_abs(cron_job_t * job_p, void handler(void),
tm_system_t * texec_p, tm_sdelta_t * tafter_p){
job_p->handler = handler;
job_p->tafter_p = tafter_p;
job_p->texec.seconds = texec_p->seconds;
job_p->texec.frac = texec_p->frac;
job_p->texec = *texec_p;
tm_cron_insert_job(job_p);
return;
}
Expand All @@ -77,6 +75,7 @@ void tm_cron_create_job_rel(cron_job_t * job_p, void handler(void),

void tm_cron_insert_job(cron_job_t * job_p){
cron_job_t * walker = cron_nextjob_p;
critical_enter();
job_p->active = 1;
if(walker == NULL){
cron_nextjob_p = job_p;
Expand Down Expand Up @@ -105,6 +104,7 @@ void tm_cron_insert_job(cron_job_t * job_p){
}
walker = walker->nextjob;
};
critical_exit();
}


Expand Down
134 changes: 74 additions & 60 deletions src/time/sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,23 @@

/**
* @file sync.c
* @brief Time synchonization function implementations.
* @brief Time synchonization function implementation
*
* Time synchronization is implemented as a state machine. The time
* synchronization state is stored in tm_sync_sm, and contains the
* state as a uint8_t and the following timestamps as tm_system_t:
* - t1 - first sync timestamp provided by the master
* - t1p - local time on receipt of the first sync timestamp
* - t2 - timestamp read by the master for delay calculation
* - t2p - master timestamped reception of t2
*
* The state machine is executed on reciept of the last synchronization
* register from the host.
*
* When the delay out timestamp is read from the host (t2), it needs to
* read one extra register. The final register read is the trigger we
* use to record our copy.
*
*
* @see sync.h
*/
Expand All @@ -34,15 +50,23 @@
#include "time.h"
#include "sync.h"

#if TIME_ENABLE_SYNC

avlt_node_t tm_avlt_sync_handler_node;
tm_sync_sm_t tm_sync_sm;
uint16_t tm_sync_host_read_hook(uint16_t address);


uint16_t tm_sync_init(uint16_t ucdm_address){
// Setup System Time Read Hook
ucdm_redirect_regr_func(ucdm_address, &tm_sync_host_read_hook);
ucdm_address += 2;

// Setup Host Interface Registers
for(uint8_t i=0; i<3; i++, ucdm_address++){
ucdm_enable_regw(ucdm_address);
for(uint8_t i=0; i<(sizeof(tm_system_t)/2); i++, ucdm_address++){
ucdm_enable_regw(ucdm_address + i);
}

// Setup Host Sync Handler(s)
ucdm_install_regw_handler(ucdm_address - 1,
&tm_avlt_sync_handler_node,
Expand All @@ -51,7 +75,6 @@ uint16_t tm_sync_init(uint16_t ucdm_address){
return ucdm_address;
}


void tm_sync_request_host(void){
ucdm_exception_status |= UCDM_EXST_TIMESYNC_REQ;
tm_sync_sm.state = TM_SYNC_STATE_WAIT_HOST;
Expand All @@ -62,83 +85,72 @@ static inline void tm_sync_apply(void);

static inline void tm_sync_apply(void){
tm_sdelta_t offset, tsd1, tsd2;
uint8_t cfrac = 0;
// tm_system_t current;

tm_get_sdelta(&(tm_sync_sm.t1), &(tm_sync_sm.t1p), &(tsd1));
tm_get_sdelta(&(tm_sync_sm.t2p), &(tm_sync_sm.t2), &(tsd2));
if (tsd1.sgn == tsd2.sgn){
offset.seconds = (tsd1.seconds + tsd2.seconds) / 2;
offset.frac = (tsd1.frac + tsd2.frac) / 2;
while (offset.frac >= TIME_TICKS_PER_SECOND){
offset.frac -= TIME_TICKS_PER_SECOND;
offset.seconds += 1;
}
offset.sgn = tsd1.sgn;
}
else{
if (tsd2.frac > tsd1.frac){
cfrac = 0;
offset.frac = tsd2.frac - tsd1.frac;
}
else{
cfrac = 1;
offset.frac = tsd1.frac - tsd2.frac;
}

if (tsd2.seconds == tsd1.seconds){
offset.seconds = 0;
offset.sgn = cfrac;
}
else if (tsd2.seconds > tsd1.seconds){
offset.sgn = 0;
offset.seconds = tsd2.seconds - offset.seconds - cfrac;
}
else{
offset.sgn = 1;
offset.seconds = tsd1.seconds - tsd2.seconds + cfrac - 1;
}
}
if (offset.sgn){
offset.sgn = 0;
}
else{
offset.sgn = 1;
}
// tm_current_time(&tm_current);
tm_apply_sdelta(&tm_current, &offset);
tm_get_sdelta(&(tm_sync_sm.t2), &(tm_sync_sm.t2p), &(tsd2));

offset = (tsd1 - tsd2)/ 2;

critical_enter();
tm_apply_sdelta((tm_system_t *)&tm_current, &offset);
critical_exit();

tm_epochchange_handler_t * echandler = epoch_handlers_root;
while(echandler){
echandler -> func(&offset);
echandler = echandler->next;
}
}

uint16_t tm_sync_host_read_hook(uint16_t address){
if (tm_sync_sm.state == TM_SYNC_STATE_WAIT_DELAY_OUT){
tm_sync_sm.state = TM_SYNC_STATE_WAIT_DELAY_IN;
// Host read our timestamp for delay calculation.
// Store the timestamp sent out
tm_current_time(&(tm_sync_sm.t2));
}
return 0;
}

void tm_sync_handler(uint16_t addr){
switch(tm_sync_sm.state){
case TM_SYNC_STATE_PREINIT:
break;
case TM_SYNC_STATE_WAIT_HOST:
case TM_SYNC_STATE_IDLE:
tm_sync_sm.state = TM_SYNC_STATE_WAIT_DELAY_OUT;
// Got the sync timestamp from the host.
tm_sync_sm.t1.seconds = ((uint32_t)(ucdm_register[addr-1].data) << 16) |
(uint32_t)(ucdm_register[addr].data);
tm_sync_sm.t1.frac = ucdm_register[addr-2].data;
if (ucdm_register[addr].data){
// Got sync with timestamp from the host.
tm_sync_sm.state = TM_SYNC_STATE_WAIT_DELAY_OUT;
memcpy(
&tm_sync_sm.t1,
(void *)&ucdm_register[addr - (sizeof(tm_system_t) / 2) + 1],
sizeof(tm_system_t)
);
} else {
// Got sync without timestamp from the host.
tm_sync_sm.state = TM_SYNC_STATE_WAIT_FOLLOW_UP;
}
tm_current_time(&(tm_sync_sm.t1p));
break;
case TM_SYNC_STATE_WAIT_FOLLOW_UP:
// Got the sync timestamp from the host.
tm_sync_sm.state = TM_SYNC_STATE_WAIT_DELAY_OUT;
memcpy(
&tm_sync_sm.t1,
(void *)&ucdm_register[addr - (sizeof(tm_system_t) / 2) + 1],
sizeof(tm_system_t)
);
break;
case TM_SYNC_STATE_WAIT_DELAY_OUT:
tm_sync_sm.state = TM_SYNC_STATE_WAIT_DELAY_IN;
// Host read our timestamp for delay calculation.
// Store the timestamp sent out
tm_current_time(&(tm_sync_sm.t2));
// This is handled in the register read function for the
// system time register of UCDM. t2 will be set there.
break;
case TM_SYNC_STATE_WAIT_DELAY_IN:
// Host returned its timestamp for delay calculation.
tm_sync_sm.t2p.seconds = ((uint32_t)(ucdm_register[addr-1].data) << 16) |
(uint32_t)(ucdm_register[addr].data);
tm_sync_sm.t2p.frac = ucdm_register[addr-2].data;
memcpy(
&tm_sync_sm.t2p,
(void *)&ucdm_register[addr - (sizeof(tm_system_t) / 2) + 1],
sizeof(tm_system_t)
);
tm_sync_sm.state = TM_SYNC_STATE_IDLE;
// All information is now available. Calculate and apply.
tm_sync_apply();
Expand All @@ -149,3 +161,5 @@ void tm_sync_handler(uint16_t addr){
}
return;
}

#endif
28 changes: 21 additions & 7 deletions src/time/sync.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@
* - epoch, as in `tm_epoch`
* - resolution of the frac, as in `TIME_SYSTICKS_PER_SECOND`
*
* Applications enabling this functionality must ensure TIME_ENABLE_SYNC
* is defined and non-zero. TM_BASE_ADDRESS as provided to `tm_init` should
* be known.
*
* The following is the general synchronization process host-side
* applications must implement to use this interface:
* - master must initiate the synchronization process by writing a
* timestamp to the appropriate UCDM registers.UCDM
*
* Utilization of this library is typically in one of three ways :
*
* - Time Initialization
Expand Down Expand Up @@ -83,8 +92,8 @@
* This is the most complicated use of this implementation, with serious
* implications to system performance. When time is synchonized, this
* implementation will pass along the offset to all subsystems which have
* stored timestamps, and all of them must apply these offsets for all
* timestamps they have which require this precision. This kind of
* stored timestamps, and all of them must apply these offsets to all
* timestamps they store which require this precision. This kind of
* synchonization is likely to have dangerous consequences to scheduled
* events and temporally marked data streams.
*
Expand All @@ -97,8 +106,9 @@
#define TM_SYNC_STATE_PREINIT 0
#define TM_SYNC_STATE_IDLE 1
#define TM_SYNC_STATE_WAIT_HOST 2
#define TM_SYNC_STATE_WAIT_DELAY_IN 3
#define TM_SYNC_STATE_WAIT_DELAY_OUT 4
#define TM_SYNC_STATE_WAIT_FOLLOW_UP 3
#define TM_SYNC_STATE_WAIT_DELAY_IN 4
#define TM_SYNC_STATE_WAIT_DELAY_OUT 5

#include <ds/avltree.h>
#include "time.h"
Expand All @@ -109,15 +119,19 @@ typedef struct TM_SYNC_SM_t{
tm_system_t t1p;
tm_system_t t2;
tm_system_t t2p;
}tm_sync_sm_t;
} tm_sync_sm_t;

#if TIME_ENABLE_SYNC
uint16_t tm_sync_init(uint16_t ucdm_next_address);
void tm_sync_request_host(void);
void tm_sync_handler(uint16_t addr);
extern avlt_node_t tm_avlt_sync_handler_node;
#endif

#if TIME_ENABLE_SYNC_RTC
uint8_t tm_sync_current_to_rtc(void);
uint8_t tm_sync_current_from_rtc(void);

extern avlt_node_t tm_avlt_sync_handler_node;
#endif

#endif

28 changes: 28 additions & 0 deletions src/time/sync_rtc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@


#include <hal/uc/rtc.h>
#include "sync.h"

tm_real_t rtc_buffer;


void tm_sync_rtc_wcb(void){
;
}

uint8_t tm_sync_current_to_rtc(void){
critical_enter();
tm_rtime_from_stime((tm_system_t *)&tm_current, &rtc_buffer);
critical_exit();
return rtc_write(&rtc_buffer, &tm_sync_rtc_wcb);
}

void tm_sync_rtc_rcb(void){
critical_enter();
tm_stime_from_rtime(&rtc_buffer, (tm_system_t *)&tm_current);
critical_exit();
}

uint8_t tm_sync_current_from_rtc(void){
return rtc_read(&rtc_buffer, &tm_sync_rtc_rcb);
}
8 changes: 1 addition & 7 deletions src/time/systick_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,5 @@
static inline void time_systick_handler(void);

static inline void time_systick_handler(void){
if (tm_current.frac == TIME_TICKS_PER_SECOND - 1){
tm_current.seconds ++;
tm_current.frac = 0;
}
else{
tm_current.frac ++;
}
tm_current ++;
}
Loading

0 comments on commit 067f21b

Please sign in to comment.