summaryrefslogtreecommitdiffstats
path: root/main/common/dallasdate.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/common/dallasdate.c')
-rw-r--r--main/common/dallasdate.c362
1 files changed, 362 insertions, 0 deletions
diff --git a/main/common/dallasdate.c b/main/common/dallasdate.c
new file mode 100644
index 0000000..31af955
--- /dev/null
+++ b/main/common/dallasdate.c
@@ -0,0 +1,362 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * dallasdate.c:
+ *
+ * Code to support the DALLAS DS1743W Timekeeping RAM plus the hooks to
+ * allow TFS to timestamp files. The function tfsTimeEnable() must be
+ * called to setup the connection between TFS and the DS1743W.
+ *
+ * Applicable to DS1743W and DS1746WP. Probably also works with other
+ * Dallas timekeepers, but the above two are the only ones I've tested
+ * it with. This code is assumed to be compiled with the DATEREGBASE
+ * value defined elsewhere. This value is the address at which the code
+ * is to access the 8-byte register map that contains the time/date
+ * information.
+ *
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "cli.h"
+
+#ifndef DATEREGBASE
+#error DATEREGBASE not defined
+#endif
+
+#define WRITE 0x80 /* part of 'cent' member */
+#define READ 0x40 /* part of 'cent' member */
+#define FT 0x40 /* part of 'wday' member */
+#define OSC_OFF 0x80 /* part of 'sec' member */
+
+/* Masks for various portions of the time/date... */
+#define YEAR10_MASK 0xf0
+#define MONTH10_MASK 0x10
+#define DATE10_MASK 0x30
+#define DAY10_MASK 0x00
+#define HOUR10_MASK 0x30
+#define MINUTE10_MASK 0x70
+#define SECOND10_MASK 0x70
+#define CENTURY10_MASK 0x30
+#define YEAR_MASK 0x0f /* Year is 0-99 */
+#define MONTH_MASK 0x0f /* Month is 1-12 */
+#define DATE_MASK 0x0f /* Date is 1-31 */
+#define DAY_MASK 0x07 /* Day is 1-7 */
+#define HOUR_MASK 0x0f /* Hour is 0-23 */
+#define MINUTE_MASK 0x0f /* Minutes is 0-59 */
+#define SECOND_MASK 0x0f /* Seconds is 0-59 */
+#define CENTURY_MASK 0x0f /* Century is 0-39 */
+
+struct dsdate {
+ uchar cent; /* B7=W, B6=R, B5-4=10cent, B3-0=cent (00-39) */
+ uchar sec; /* B7=OSC; B6-4=10secs; B3-0=sec (0-59) */
+ uchar min; /* B6-4=10mins; B3-0=min (0-59) */
+ uchar hour; /* B4-5=10hour; B3-0=hour (0-23) */
+ uchar wday; /* B6=FT B2-0=day (1-7) */
+ uchar mday; /* B4-5=10date; B3-0=date (1-31) */
+ uchar month; /* B4=10mo; B3-0=month (1-12) */
+ uchar year; /* MS-nibble=10Year; LS-nibble=year (0-99) */
+};
+
+#define DS1743REGS ((struct dsdate *)DATEREGBASE)
+#define DS_century (DS1743REGS->cent)
+#define DS_second (DS1743REGS->sec)
+#define DS_minute (DS1743REGS->min)
+#define DS_hour (DS1743REGS->hour)
+#define DS_wday (DS1743REGS->wday)
+#define DS_mday (DS1743REGS->mday)
+#define DS_month (DS1743REGS->month)
+#define DS_year (DS1743REGS->year)
+
+#define SECONDS_IN_DAY 86400
+
+static char
+DaysInMonth[] = {
+ 31, 28, 31, 30, 31, 30, /* Jan, Feb, Mar, Apr, May, Jun */
+ 31, 31, 30, 31, 30, 31 /* Jul, Aug, Sep, Oct, Nov, Dec */
+};
+
+/* rangecheck():
+ Return 0 if value is outside the range of high and low; else 1.
+*/
+static int
+rangecheck(int value, char *name, int low, int high)
+{
+ if ((value < low) || (value > high)) {
+ printf("%s outside valid range of %d - %d\n",
+ name,low,high);
+ return(0);
+ }
+ return(1);
+}
+
+/* to_dsdatefmt():
+ * Take an incoming integer and convert it to the dallas time date
+ * format using a 10-multiplier for the upper nibble.
+ */
+static unsigned char
+to_dsdatefmt(int value)
+{
+ int tens;
+
+ tens = 0;
+ while (value >= 10) {
+ tens++;
+ value -= 10;
+ }
+ return((tens << 4) | value);
+}
+
+static int
+from_dsdatefmt(unsigned char value, unsigned char mask10)
+{
+ int newvalue;
+
+ newvalue = value & 0x0f;
+ newvalue += 10 * ((value & mask10) >> 4);
+ return(newvalue);
+}
+
+int
+showDate(int center)
+{
+ int (*pfunc)(char *, ...);
+ int day, date, month, year, hour, minute, second, century;
+
+ DS_century |= READ; /* Set READ bit */
+
+ century = from_dsdatefmt(DS_century,CENTURY10_MASK);
+ second = from_dsdatefmt(DS_second,SECOND10_MASK);
+ minute = from_dsdatefmt(DS_minute,MINUTE10_MASK);
+ hour = from_dsdatefmt(DS_hour,HOUR10_MASK);
+ day = from_dsdatefmt(DS_wday,DAY10_MASK);
+ date = from_dsdatefmt(DS_mday,DATE10_MASK);
+ month = from_dsdatefmt(DS_month,MONTH10_MASK);
+ year = (((DS_year & 0xf0) >> 4) * 10) + (DS_year & 0x0f);
+
+ DS_century &= ~READ; /* Clear READ bit */
+
+ if (center)
+ pfunc = cprintf;
+ else
+ pfunc = printf;
+
+ pfunc("%02d/%02d/%02d%02d @ %02d:%02d:%02d\n",
+ month,date,century,year,hour,minute,second);
+
+ return(0);
+}
+
+#if INCLUDE_TFS
+
+static int
+YearIsLeap(int year)
+{
+ if (year % 4) /* if year not divisible by 4... */
+ return(0); /* it's not leap */
+ if (year < 1582) /* all years divisible by 4 were */
+ return(1); /* leap prior to 1582 */
+ if (year % 100) /* if year divisible by 4, */
+ return(1); /* but not by 100, it's leap */
+ if (year % 400) /* if year divisible by 100, */
+ return(0); /* but not by 400, it's not leap */
+ else
+ return(1); /* if divisible by 400, it's leap */
+}
+
+/* GetAtime():
+ * Build a string based on the incoming long value as described in
+ * GetLtime()...
+ * Used by TFS to keep track of file time.
+ */
+static char *
+GetAtime(long tval, char *buf, int bsize)
+{
+ int year; /* Actual year */
+ int doy; /* Day of year */
+ int sid; /* Seconds in day */
+ int leapyear; /* Set if year is leap */
+ int month, hour, minute;
+
+ if ((bsize < 18) || (tval == TIME_UNDEFINED)) {
+ *buf = 0;
+ return(buf);
+ }
+
+ /* Break down the basic bitfields: */
+ year = 2000 + ((tval >> 26) & 0x3f);
+ leapyear = YearIsLeap(year);
+ doy = ((tval >> 17) & 0x1ff);
+ sid = tval & 0x1ffff;
+
+ /* Now build the date from the bit fields: */
+ hour = sid / 3600;
+ sid -= (hour*3600);
+ minute = sid/60;
+ sid -= (minute*60);
+
+ month = 0;
+ while(doy > DaysInMonth[month]) {
+ doy -= DaysInMonth[month];
+ if ((month == 1) && (leapyear))
+ doy--;
+ month++;
+ }
+ sprintf(buf,"%02d/%02d/%02d@%02d:%02d:%02d",
+ month+1,doy,year,hour,minute,sid);
+ return(buf);
+}
+
+/* GetLtime():
+ * Build a long with the following format....
+ *
+ * B31-26 year since 2000 (0-127 yep, this breaks in 2128)
+ * B25-17 day of year (1-365)
+ * B16-0 seconds in day (0-86400)
+ *
+ * Used by TFS to keep track of file time.
+ */
+static long
+GetLtime(void)
+{
+ long tval;
+ int year, month, mday, seconds, doy, leapyear;
+
+ DS_century |= READ; /* Set READ bit */
+
+ year = from_dsdatefmt(DS_year,YEAR10_MASK); /* 00=2000 */
+ month = from_dsdatefmt(DS_month,MONTH10_MASK)-1; /* 0-11 */
+ mday = from_dsdatefmt(DS_mday,DATE10_MASK); /* 1-31 */
+ leapyear = YearIsLeap(year+2000);
+
+ if ((month > 11) || (month < 0) || (mday < 1) || (mday > 31))
+ return(TIME_UNDEFINED);
+
+ /* Determine current day of year... */
+ doy = mday;
+ while(month > 0) {
+ doy += DaysInMonth[month-1];
+ if ((month == 1) && leapyear)
+ doy++;
+ month--;
+ }
+
+ /* Determine current second of day... */
+ seconds = (from_dsdatefmt(DS_hour,HOUR10_MASK) * 3600);
+ seconds += (from_dsdatefmt(DS_minute,MINUTE10_MASK) * 60);
+ seconds += from_dsdatefmt(DS_second,SECOND10_MASK);
+
+ DS_century &= ~READ; /* Clear READ bit */
+
+ tval = (((year & 0x3f) << 26) |
+ ((doy & 0x1ff) << 17) |
+ (seconds & 0x1ffff));
+ return(tval);
+}
+
+/* tfsTimeEnable():
+ * Hook the file timestamping in TFS to the DS1743 device...
+ */
+void
+tfsTimeEnable(void)
+{
+ tfsctrl(TFS_TIMEFUNCS,(long)GetLtime,(long)GetAtime);
+}
+#endif
+
+char *DateHelp[] = {
+ "Display (mm/dd/yyyy@hh:mm:ss) or modify time and date.",
+ "[{day date month year hour min sec}]",
+#if INCLUDE_VERBOSEHELP
+ "Where...",
+ " day: 1-7 (sun=1)",
+ " date: 1-31",
+ " month: 1-12",
+ " year: 0-3899",
+ " hour: 0-23",
+ " min: 0-59",
+ " sec: 0-59",
+ "Note: 'date off' disables the oscillator",
+#endif
+ 0
+};
+
+int
+Date(int argc,char *argv[])
+{
+ int day, date, month, year, hour, minute, second, century, rngchk;
+
+ if (argc == 1) {
+ if (DS_second & OSC_OFF)
+ printf("Warning: oscillator disabled.\n");
+ showDate(0);
+ return(CMD_SUCCESS);
+ }
+ else if ((argc == 2) && !strcmp(argv[1],"off")) {
+ DS_century |= WRITE; /* Disable the oscillator */
+ DS_second = OSC_OFF; /* to save battery life. */
+ DS_century &= ~WRITE;
+ return(CMD_SUCCESS);
+ }
+ else if (argc != 8)
+ return(CMD_PARAM_ERROR);
+
+ day = atoi(argv[1]);
+ date = atoi(argv[2]);
+ month = atoi(argv[3]);
+ year = atoi(argv[4]);
+ hour = atoi(argv[5]);
+ minute = atoi(argv[6]);
+ second = atoi(argv[7]);
+
+ rngchk = 0;
+ rngchk += rangecheck(day,"day",1,7);
+ rngchk += rangecheck(date,"date",1,31);
+ rngchk += rangecheck(month,"month",1,12);
+ rngchk += rangecheck(year,"year",0,3899);
+ rngchk += rangecheck(hour,"hour",0,23);
+ rngchk += rangecheck(minute,"minute",0,59);
+ rngchk += rangecheck(second,"second",0,59);
+
+ if (rngchk != 7)
+ return(CMD_PARAM_ERROR);
+
+ DS_century = WRITE; /* Set WRITE bit */
+ DS_second = to_dsdatefmt(second) & ~OSC_OFF;
+ DS_minute = to_dsdatefmt(minute);
+ DS_hour = to_dsdatefmt(hour);
+ DS_wday = day;
+ DS_mday = to_dsdatefmt(date);
+ DS_month = to_dsdatefmt(month);
+ century = year / 100;
+ year = year % 100;
+ DS_year = to_dsdatefmt(year);
+ DS_century = (to_dsdatefmt(century)&(CENTURY_MASK|CENTURY10_MASK))|WRITE;
+
+ DS_century &= ~WRITE; /* Clear WRITE bit */
+ return(CMD_SUCCESS);
+}
+
+