// Copyright 2017 Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland // www.source-code.biz, www.inventec.ch/chdh // // This module is multi-licensed and may be used under the terms of any of the following licenses: // // LGPL, GNU Lesser General Public License, V2.1 or later, http://www.gnu.org/licenses/lgpl.html // EPL, Eclipse Public License, V1.0 or later, http://www.eclipse.org/legal // // Please contact the author if you need another license. // This module is provided "as is", without warranties of any kind. // // Home page: http://www.source-code.biz/snippets/java/I2cBusDriver package biz.source_code.utils; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.Locale; import java.util.TimeZone; // Driver for the PCF8563 RTC (real-time clock) chip. public class PCF8563Driver { private static final int slaveAddr = 0x51; private static final TimeZone GMT = TimeZone.getTimeZone("GMT"); // Returns 0 if the RTC time is not valid, which is normally caused by a low battery. public static long getTime (I2cBusDriver i2c) throws Exception { byte[] d = i2c.getRegs(slaveAddr, 2, 7); if ((d[0] & 0x80) != 0) { return 0; } int second = decodeBcd(d[0] & 0x7F); int minute = decodeBcd(d[1] & 0x7F); int hour = decodeBcd(d[2] & 0x3F); int day = decodeBcd(d[3] & 0x3F); int month = decodeBcd(d[5] & 0x1F); int year = decodeBcd(d[6] & 0xFF) + (((d[5] & 0x80) != 0) ? 1900 : 2000); // same logic as Uboot GregorianCalendar cal = new GregorianCalendar(GMT, Locale.US); cal.clear(); cal.set(year, Math.max(0, month - 1), day, hour, minute, second); return cal.getTimeInMillis(); } public static void setTime (I2cBusDriver i2c, long time) throws Exception { GregorianCalendar cal = new GregorianCalendar(GMT, Locale.US); cal.setTimeInMillis(time); int year = cal.get(Calendar.YEAR); int month = cal.get(Calendar.MONTH) + 1; int day = cal.get(Calendar.DAY_OF_MONTH); int hour = cal.get(Calendar.HOUR_OF_DAY); int minute = cal.get(Calendar.MINUTE); int second = cal.get(Calendar.SECOND); int weekDay = (cal.get(Calendar.DAY_OF_WEEK) + 6) % 7; // Sunday = 0 byte[] d = new byte[16]; d[0] = 0x00; d[1] = 0x00; d[2] = encodeBcd(second); d[3] = encodeBcd(minute); d[4] = encodeBcd(hour); d[5] = encodeBcd(day); d[6] = (byte)weekDay; d[7] = (byte)(((year >= 2000 && year <= 2099) ? 0x00 : 0x80) | encodeBcd(month)); d[8] = (year >= 1900 && year <= 2099) ? encodeBcd(year % 100) : 0; d[9] = (byte)0x80; d[10] = (byte)0x80; d[11] = (byte)0x80; d[12] = (byte)0x80; d[13] = (byte)0x00; d[14] = (byte)0x03; d[15] = (byte)0x00; i2c.setRegs(slaveAddr, 0, d); } private static int decodeBcd (int i) { int hi = (i & 0xF0) >> 4; int lo = (i & 0x0F); return hi * 10 + lo; } private static byte encodeBcd (int i) { if (i > 99 || i < 0) { return 0; } int hi = i / 10; int lo = i % 10; return (byte)((hi << 4) | lo); } }