Add CRC16 with reverse bit order
authorNils Faerber <nils@tlb.(none)>
Tue, 19 Jul 2011 10:31:32 +0000 (12:31 +0200)
committerNils Faerber <nils@tlb.(none)>
Tue, 19 Jul 2011 10:31:32 +0000 (12:31 +0200)
Makefile
crc16ccitt.c [new file with mode: 0644]
crc16ccitt.h [new file with mode: 0644]
metawatch.c
metawatch_protocol.h

index e605bc2..4024ec9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ CFLAGS = $(CCFLAGS)
 
 PRGNAME = metawatch
 
-MEMBERS = metawatch
+MEMBERS = metawatch crc16ccitt
 
 # no need to change anything below this line
 # ------------------------------------------
diff --git a/crc16ccitt.c b/crc16ccitt.c
new file mode 100644 (file)
index 0000000..d468c80
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * derived from crctester.c
+ * original header:
+ * ----------------------------------------------------------------------------
+ * CRC tester v1.3 written on 4th of February 2003 by Sven Reifegerste (zorc/reflex)
+ * This is the complete compilable C program, consisting only of this .c file.
+ * No guarantee for any mistakes.
+ *
+ * changes to CRC tester v1.2:
+ *
+ * - remove unneccessary (!(polynom&1)) test for invalid polynoms
+ *   (now also XMODEM parameters 0x8408 work in c-code as they should)
+ *
+ * changes to CRC tester v1.1:
+ *
+ * - include an crc&0crcmask after converting non-direct to direct initial
+ *   value to avoid overflow
+ *
+ * changes to CRC tester v1.0:
+ *
+ * - most int's were replaced by unsigned long's to allow longer input strings
+ *   and avoid overflows and unnecessary type-casting's
+ * ----------------------------------------------------------------------------
+ */
+
+static const int order = 16;
+static const unsigned long polynom = 0x1021;
+static const int direct = 1;
+static const unsigned long crcinit = 0xffff;
+static const unsigned long crcxor = 0x0000;
+static const int refin = 1;
+static const int refout = 0;
+
+// 'order' [1..32] is the CRC polynom order, counted without the leading '1' bit
+// 'polynom' is the CRC polynom without leading '1' bit
+// 'direct' [0,1] specifies the kind of algorithm: 1=direct, no augmented zero bits
+// 'crcinit' is the initial CRC value belonging to that algorithm
+// 'crcxor' is the final XOR value
+// 'refin' [0,1] specifies if a data byte is reflected before processing (UART) or not
+// 'refout' [0,1] specifies if the CRC will be reflected before XOR
+
+
+// internal global values:
+
+static unsigned long crcmask;
+static unsigned long crchighbit;
+static unsigned long crcinit_direct;
+static unsigned long crcinit_nondirect;
+static unsigned long crctab[256];
+
+
+// subroutines
+
+static unsigned long reflect (unsigned long crc, int bitnum) {
+
+       // reflects the lower 'bitnum' bits of 'crc'
+
+       unsigned long i, j=1, crcout=0;
+
+       for (i=(unsigned long)1<<(bitnum-1); i; i>>=1) {
+               if (crc & i) crcout|=j;
+               j<<= 1;
+       }
+       return (crcout);
+}
+
+
+
+static void generate_crc_table(void)
+{
+       // make CRC lookup table used by table algorithms
+
+       int i, j;
+       unsigned long bit, crc;
+
+       for (i=0; i<256; i++) {
+
+               crc=(unsigned long)i;
+               if (refin) crc=reflect(crc, 8);
+               crc<<= order-8;
+
+               for (j=0; j<8; j++) {
+
+                       bit = crc & crchighbit;
+                       crc<<= 1;
+                       if (bit) crc^= polynom;
+               }                       
+
+               if (refin) crc = reflect(crc, order);
+               crc&= crcmask;
+               crctab[i]= crc;
+       }
+}
+
+
+static unsigned long crctablefast (unsigned char* p, unsigned long len)
+{
+       // fast lookup table algorithm without augmented zero bytes, e.g. used in pkzip.
+       // only usable with polynom orders of 8, 16, 24 or 32.
+
+       unsigned long crc = crcinit_direct;
+
+       if (refin) crc = reflect(crc, order);
+
+       if (!refin) while (len--) crc = (crc << 8) ^ crctab[ ((crc >> (order-8)) & 0xff) ^ *p++];
+       else while (len--) crc = (crc >> 8) ^ crctab[ (crc & 0xff) ^ *p++];
+
+       if (refout^refin) crc = reflect(crc, order);
+       crc^= crcxor;
+       crc&= crcmask;
+
+       return(crc);
+}
+
+static unsigned long crctable (unsigned char* p, unsigned long len)
+{
+       // normal lookup table algorithm with augmented zero bytes.
+       // only usable with polynom orders of 8, 16, 24 or 32.
+
+       unsigned long crc = crcinit_nondirect;
+
+       if (refin)
+               crc = reflect(crc, order);
+
+       if (!refin)
+               while (len--)
+                       crc = ((crc << 8) | *p++) ^ crctab[ (crc >> (order-8))  & 0xff];
+       else
+               while (len--)
+                       crc = ((crc >> 8) | (*p++ << (order-8))) ^ crctab[ crc & 0xff];
+
+       if (!refin)
+               while (++len < order/8)
+                       crc = (crc << 8) ^ crctab[ (crc >> (order-8))  & 0xff];
+       else
+               while (++len < order/8)
+                       crc = (crc >> 8) ^ crctab[crc & 0xff];
+
+       if (refout^refin)
+               crc = reflect(crc, order);
+       crc^= crcxor;
+       crc&= crcmask;
+
+       return(crc);
+}
+
+
+
+unsigned long crcbitbybit(unsigned char* p, unsigned long len) {
+
+       // bit by bit algorithm with augmented zero bytes.
+       // does not use lookup table, suited for polynom orders between 1...32.
+
+       unsigned long i, j, c, bit;
+       unsigned long crc = crcinit_nondirect;
+
+       for (i=0; i<len; i++) {
+
+               c = (unsigned long)*p++;
+               if (refin)
+                       c = reflect(c, 8);
+
+               for (j=0x80; j; j>>=1) {
+                       bit = crc & crchighbit;
+                       crc<<= 1;
+                       if (c & j)
+                               crc|= 1;
+                       if (bit)
+                               crc^= polynom;
+               }
+       }       
+
+       for (i=0; i<order; i++) {
+               bit = crc & crchighbit;
+               crc <<= 1;
+               if (bit)
+                       crc^= polynom;
+       }
+
+       if (refout)
+               crc=reflect(crc, order);
+       crc ^= crcxor;
+       crc &= crcmask;
+
+       return(crc);
+}
+
+
+
+unsigned long crcbitbybitfast(unsigned char* p, unsigned long len) {
+
+       // fast bit by bit algorithm without augmented zero bytes.
+       // does not use lookup table, suited for polynom orders between 1...32.
+
+       unsigned long i, j, c, bit;
+       unsigned long crc = crcinit_direct;
+
+       for (i=0; i<len; i++) {
+               c = (unsigned long)*p++;
+               if (refin)
+                       c = reflect(c, 8);
+
+               for (j=0x80; j; j>>=1) {
+                       bit = crc & crchighbit;
+                       crc <<= 1;
+                       if (c & j)
+                               bit^= crchighbit;
+                       if (bit)
+                               crc^= polynom;
+               }
+       }       
+
+       if (refout)
+               crc=reflect(crc, order);
+       crc^= crcxor;
+       crc&= crcmask;
+
+       return(crc);
+}
+
+void crc16ccitt_init(void)
+{
+       int i;
+       unsigned long bit, crc;
+
+       crcmask = ((((unsigned long)1<<(order-1))-1)<<1)|1;
+       crchighbit = (unsigned long)1<<(order-1);
+
+       generate_crc_table();
+
+       if (!direct) {
+               crcinit_nondirect = crcinit;
+               crc = crcinit;
+               for (i=0; i<order; i++) {
+                       bit = crc & crchighbit;
+                       crc <<= 1;
+                       if (bit)
+                               crc^= polynom;
+               }
+               crc &= crcmask;
+               crcinit_direct = crc;
+       } else {
+               crcinit_direct = crcinit;
+               crc = crcinit;
+               for (i=0; i<order; i++) {
+                       bit = crc & 1;
+                       if (bit)
+                               crc^= polynom;
+                       crc >>= 1;
+                       if (bit)
+                               crc|= crchighbit;
+               }       
+               crcinit_nondirect = crc;
+       }
+}
+
+unsigned short crc16ccitt (unsigned char *data, int len)
+{
+       // call CRC algorithms using the CRC parameters above and print result to the console
+       return crcbitbybitfast((unsigned char *)data, len);
+}
+
+#if 0
+int main() {
+
+       // test program for checking four different CRC computing types that are:
+       // crcbit(), crcbitfast(), crctable() and crctablefast(), see above.
+       // parameters are at the top of this program.
+       // Result will be printed on the console.
+
+       int i;
+       unsigned long bit, crc;
+
+
+       // at first, compute constant bit masks for whole CRC and CRC high bit
+
+       crcmask = ((((unsigned long)1<<(order-1))-1)<<1)|1;
+       crchighbit = (unsigned long)1<<(order-1);
+
+
+       // check parameters
+
+       if (order < 1 || order > 32) {
+               printf("ERROR, invalid order, it must be between 1..32.\n");
+               return(0);
+       }
+
+       if (polynom != (polynom & crcmask)) {
+               printf("ERROR, invalid polynom.\n");
+               return(0);
+       }
+
+       if (crcinit != (crcinit & crcmask)) {
+               printf("ERROR, invalid crcinit.\n");
+               return(0);
+       }
+
+       if (crcxor != (crcxor & crcmask)) {
+               printf("ERROR, invalid crcxor.\n");
+               return(0);
+       }
+
+       
+       // generate lookup table
+
+       generate_crc_table();
+
+
+       // compute missing initial CRC value
+
+       if (!direct) {
+
+               crcinit_nondirect = crcinit;
+               crc = crcinit;
+               for (i=0; i<order; i++) {
+
+                       bit = crc & crchighbit;
+                       crc<<= 1;
+                       if (bit) crc^= polynom;
+               }
+               crc&= crcmask;
+               crcinit_direct = crc;
+       }
+
+       else {
+
+               crcinit_direct = crcinit;
+               crc = crcinit;
+               for (i=0; i<order; i++) {
+
+                       bit = crc & 1;
+                       if (bit) crc^= polynom;
+                       crc >>= 1;
+                       if (bit) crc|= crchighbit;
+               }       
+               crcinit_nondirect = crc;
+       }
+       
+
+       // call CRC algorithms using the CRC parameters above and print result to the console
+
+       printf("\n");
+       printf("CRC tester v1.1 written on 13/01/2003 by Sven Reifegerste (zorc/reflex)\n");
+       printf("-----------------------------------------------------------------------\n");
+       printf("\n");
+       printf("Parameters:\n");
+       printf("\n");
+       printf(" polynom             :  0x%x\n", polynom);
+       printf(" order               :  %d\n", order);
+       printf(" crcinit             :  0x%x direct, 0x%x nondirect\n", crcinit_direct, crcinit_nondirect);
+       printf(" crcxor              :  0x%x\n", crcxor);
+       printf(" refin               :  %d\n", refin);
+       printf(" refout              :  %d\n", refout);
+       printf("\n");
+       printf(" data string         :  '%s' (%d bytes)\n", string, strlen(string));
+       printf("\n");
+       printf("Results:\n");
+       printf("\n");
+
+       printf(" crc bit by bit      :  0x%x\n", crcbitbybit((unsigned char *)string, strlen(string)));
+       printf(" crc bit by bit fast :  0x%x\n", crcbitbybitfast((unsigned char *)string, strlen(string)));
+       if (!(order&7)) printf(" crc table           :  0x%x\n", crctable((unsigned char *)string, strlen(string)));
+       if (!(order&7)) printf(" crc table fast      :  0x%x\n", crctablefast((unsigned char *)string, strlen(string)));
+
+       return(0);
+}
+#endif
diff --git a/crc16ccitt.h b/crc16ccitt.h
new file mode 100644 (file)
index 0000000..d9ade56
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _CRC16_h
+#define _CRC16_H
+
+void crc16ccitt_init(void);
+unsigned short crc16ccitt (unsigned char *data, int len);
+
+#endif
index 7305b03..c6914ce 100644 (file)
@@ -7,23 +7,90 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <string.h>
+#include <time.h>
 
 #include "metawatch_protocol.h"
+#include "crc16ccitt.h"
+
+
+void dump_frame(unsigned char *frame, int len)
+{
+  int i;
+  for (i=0; i<len; i++)
+    fprintf(stderr, "0x%02x ", frame[i]);
+  fprintf(stderr, "\n");
+}
+
+
+void mw_send_packet(int mw_fd, unsigned char msg_type, unsigned char options, unsigned char *data, unsigned char len)
+{
+  unsigned short crc;
+  unsigned char frame[64];
+
+  memset(frame, 0, 64);
+  frame[0] = MW_SOF;
+  frame[1] = len + 6;
+  frame[2] = msg_type;
+  frame[3] = options;
+  memcpy(frame+4, data, len);
+  
+  crc = crc16ccitt(frame, len+4);
+  *(unsigned short *)(frame+len+4) = crc;
+
+  dump_frame(frame, len+6);
+
+  write(mw_fd, frame, len+6);
+}
+
+void mw_set_rtc(int mw_fd, unsigned char clk1224, unsigned char date_fmt)
+{
+  time_t mtime;
+  struct tm mtm;
+  unsigned short year;
+  unsigned char data[32];
+  
+  mtime = time(NULL);
+  localtime_r(&mtime, &mtm);
+
+  year = mtm.tm_year + 1900;  
+  data[0] = (year & 0x0f00) >> 8;
+  data[1] = (year & 0x00ff);
+  data[2] = mtm.tm_mon + 1;
+  data[3] = mtm.tm_mday;
+  data[4] = mtm.tm_wday;
+  data[5] = mtm.tm_hour;
+  data[6] = mtm.tm_min;
+  data[7] = mtm.tm_sec;
+  data[8] = clk1224;
+  data[9] = date_fmt;
+
+  mw_send_packet(mw_fd, MW_SET_REAL_TIME_CLOCK, 0, data, 10);
+}
+
 
 int main(int argc, char **argv)
 {
-  int mwfd;
+  int mw_fd;
 
   if (argc != 2) {
     fprintf(stderr, "Usage:\n\t%s <devicename>\n", argv[0]);
     return 1;
   };
   
-  mwfd = open(argv[1], O_RDWR);
-  if (mwfd < 0) {
+  crc16ccitt_init();
+
+  mw_fd = open(argv[1], O_RDWR);
+  if (mw_fd < 0) {
     perror("open");
     return 1;
   };
 
+  mw_set_rtc(mw_fd, MW_RTC_CLOCK_24HR, MW_RTC_DATE_DDMM);
+
+  fsync(mw_fd);
+
+  close(mw_fd);
+
   return 0;
 };
index cae11c9..c08b601 100644 (file)
 #define MW_GET_REAL_TIME_CLOCK         0x27
 #define MW_GET_REAL_TIME_CLOCK_RSP     0x28
 
+#define MW_RTC_CLOCK_12HR              0x00
+#define MW_RTC_CLOCK_24HR              0x01
+#define MW_RTC_DATE_MMDD               0x00
+#define MW_RTC_DATE_DDMM               0x01
+
 #define MW_RESERVED                    0x32
 #define MW_STATUS_CHANGE_EVENT         0x33
 #define MW_BUTTON_EVENT_MESSAGE                0x34