Alex exoskeleton
ALEX SoftwareDocumentation
CO_time.c
Go to the documentation of this file.
1 /*
2  * CANopen time interface.
3  *
4  * @file CO_time.c
5  * @author Janez Paternoster
6  * @copyright 2016 Janez Paternoster
7  *
8  * This file is part of CANopenSocket, a Linux implementation of CANopen
9  * stack with master functionality. Project home page is
10  * <https://github.com/CANopenNode/CANopenSocket>. CANopenSocket is based
11  * on CANopenNode: <https://github.com/CANopenNode/CANopenNode>.
12  *
13  * CANopenSocket is free and open source software: you can redistribute
14  * it and/or modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation, either version 2 of the
16  * License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program. If not, see <http://www.gnu.org/licenses/>.
25  */
26 
27 
28 #include "CO_time.h"
29 #include <time.h>
30 #include <string.h>
31 
32 
33 /* Set epochTime base and offset */
34 static void timeZero(CO_time_t *tm) {
35  struct timespec tspec;
36  struct tm *tstruct;
37 
38  clock_gettime(CLOCK_REALTIME, &tspec);
39  tstruct = localtime(&tspec.tv_sec);
40 
41  /* epochTimeBaseMs is rounded to minutes, 0 seconds, 0 ms. */
42  *tm->epochTimeBaseMs = ((uint64_t) (tspec.tv_sec - tstruct->tm_sec)) * 1000;
43  *tm->epochTimeOffsetMs = (tspec.tv_nsec / 1000000) + (tstruct->tm_sec * 1000);
44 }
45 
46 
47 /* OD function for accessing _OD_time_ (index 0x2130) from SDO server.
48  * For more information see file CO_SDO.h. */
49 static CO_SDO_abortCode_t CO_ODF_time(CO_ODF_arg_t *ODF_arg) {
50  CO_time_t *tm;
51  CO_SDO_abortCode_t ret = CO_SDO_AB_NONE;
52 
53  tm = (CO_time_t*) ODF_arg->object;
54 
55  /* Reading Object Dictionary variable */
56  if(ODF_arg->reading) {
57 
58  /* return current time as string */
59  if(ODF_arg->subIndex == 1){
60  time_t t;
61  char* timeString;
62 
63  t = time(NULL);
64  timeString = ctime(&t);
65 
66  strncpy((char*) ODF_arg->data, timeString, ODF_arg->dataLength);
67  ODF_arg->data[ODF_arg->dataLength - 1] = 0;
68  }
69  }
70  else {
71  if(ODF_arg->subIndex == 3) { /* write zero to epochTimeOffsetMs */
72  uint32_t *value = (uint32_t*) ODF_arg->data;
73 
74  if(*value == 0) {
75  timeZero(tm);
76  *value = *tm->epochTimeOffsetMs;
77  }
78  else {
79  ret = CO_SDO_AB_INVALID_VALUE;
80  }
81  }
82  }
83 
84  return ret;
85 }
86 
87 
88 /******************************************************************************/
90  CO_time_t *tm,
91  CO_SDO_t *SDO,
92  uint64_t *epochTimeBaseMs,
93  uint32_t *epochTimeOffsetMs,
94  uint16_t idx_OD_time)
95 {
96 
97  tm->epochTimeBaseMs = epochTimeBaseMs;
98  tm->epochTimeOffsetMs = epochTimeOffsetMs;
99 
100  if(*epochTimeBaseMs == 0) {
101  timeZero(tm);
102  }
103 
104  CO_OD_configure(SDO, idx_OD_time, CO_ODF_time, (void*)tm, 0, 0);
105 }
106 
107 
108 /******************************************************************************/
110 
111  if(++(*tm->epochTimeOffsetMs) == 0) {
112  /* overflow happened after ~50 days */
113  timeZero(tm);
114  }
115 }
void CO_time_init(CO_time_t *tm, CO_SDO_t *SDO, uint64_t *epochTimeBaseMs, uint32_t *epochTimeOffsetMs, uint16_t idx_OD_time)
Definition: CO_time.c:89
void CO_time_process(CO_time_t *tm)
Definition: CO_time.c:109
uint64_t * epochTimeBaseMs
Definition: CO_time.h:38
char ret[STRING_BUFFER_SIZE]
Definition: application.cpp:15
Time object, usable for timestamping - Defined in CANOpen code.
Definition: CO_time.h:37
unsigned short uint16_t
Definition: CO_command.h:35
unsigned int uint32_t
Definition: CO_command.h:31
uint32_t * epochTimeOffsetMs
Definition: CO_time.h:39