gclark@utcsri.UUCP (09/06/87)
Here is part 2 of my Amiga real-time clock design, containing the sources for the clock software. Graeme Clark -- Dept. of Computer Science, Univ. of Toronto, Canada M5S 1A4 {allegra,cornell,decvax,ihnp4,linus,utzoo}!utcsri!gclark gclark@csri.toronto.edu ----------------- cut here ----------------------------------- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # makefile # clockwr.c # clockrd.c # clocktest.c # nice_time.h # This archive created: Sat Aug 29 19:59:54 1987 export PATH; PATH=/bin:$PATH echo shar: extracting "'makefile'" '(359 characters)' if test -f 'makefile' then echo shar: will not over-write existing file "'makefile'" else cat << \SHAR_EOF > 'makefile' # Makefile for clock programs, Manx 3.4a clockrd : clockrd.o ln -o clockrd clockrd.o -lc clockwr : clockwr.o ln -o clockwr clockwr.o -lc clocktest : clocktest.o ln -o clocktest clocktest.o -lc clockrd.o : clockrd.c nice_time.h cc clockrd.c clockwr.o : clockwr.c nice_time.h cc clockwr.c clocktest.o : clocktest.c nice_time.h cc clocktest.c SHAR_EOF if test 359 -ne "`wc -c < 'makefile'`" then echo shar: error transmitting "'makefile'" '(should have been 359 characters)' fi fi # end of overwriting check echo shar: extracting "'clockwr.c'" '(14906 characters)' if test -f 'clockwr.c' then echo shar: will not over-write existing file "'clockwr.c'" else cat << \SHAR_EOF > 'clockwr.c' #include <stdio.h> #include <exec/types.h> #include <hardware/custom.h> #include <hardware/cia.h> #include <resources/potgo.h> #include <devices/timer.h> #include <functions.h> #include "nice_time.h" /********************************************************************** * clockwr -- prompt for the time and date, and set the hardware and * * software clocks * * usage: clockwr * **********************************************************************/ main() { struct nice_time tm; long seconds; void set_time(), print_time(), term_port(); int init_port(), input_time(), check_time(), set_sys_time(); long nice_to_sec(); if (init_port() != 0) exit(1); if (input_time(&tm) != -1) { if (check_time(&tm) == -1) { printf("That doesn't look like a real date to me, so I'm\n"); printf("not going to bother to set the clocks.\n"); } else { printf("Setting hardware clock..."); fflush(stdout); set_time(&tm); printf("\nSetting software clock..."); fflush(stdout); seconds = nice_to_sec(&tm); (void)set_sys_time(seconds); printf("\nTime set to "); print_time(&tm); printf("Done.\n"); } } term_port(); } /********************************************************************** * input_time() -- prompt for the time and date and place in the * * given nice_time structure * * returns 0 normally, -1 if error * **********************************************************************/ int input_time(tm) struct nice_time *tm; { int get_int(); printf("If you goof or change your mind and don't want to set the\n"); printf("clocks, just press return\n"); printf("\n"); if ((tm->year = get_int("Year, e.g. 1986")) == -1) return(-1); if ((tm->month = get_int("Month (1..12)" )) == -1) return(-1); if ((tm->day = get_int("Day (1..31)" )) == -1) return(-1); if ((tm->day_of_week = get_int("Day of Week (0=Sun, ..., 6=Sat)")) == -1) return(-1); if ((tm->hour = get_int("Hour (0..23)" )) == -1) return(-1); if ((tm->minute = get_int("Minute (0..59)" )) == -1) return(-1); tm->second = 0; return(0); } /********************************************************************** * get_int() -- display the given prompt and read an integer, * * returning it or -1 if a blank line is input * **********************************************************************/ int get_int(prompt) char *prompt; { char buf[80]; char *cp; int atoi(); void getline(); printf("%s: ", prompt); fflush(stdout); getline(buf); for (cp=buf; *cp == ' '; ++cp) ; if (*cp == '\0') return(-1); else return(atoi(cp)); } /********************************************************************** * getline() -- read a line from stdin * **********************************************************************/ void getline(buf) char *buf; { int ch; while ((ch = getchar()) != '\n' && ch != EOF) *buf++ = ch; *buf = '\0'; } /********************************************************************** * print_time() -- display the contents of a nice_time structure * **********************************************************************/ void print_time(tm) struct nice_time *tm; { static char *mnames[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; static char *dnames[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; printf("%-9s %2d-%s-%02d %2d:%02d:%02d", dnames[tm->day_of_week], tm->day, mnames[tm->month-1], tm->year % 100, (tm->hour==0) ? 12 : (tm->hour<=12) ? tm->hour : tm->hour-12, tm->minute, tm->second); if (tm->hour < 12) printf(" AM\n"); else printf(" PM\n"); } /********************************************************************** * nice_to_sec() -- convert the given nice_time structure into * * seconds since 00:00:00 January 1, 1978 * **********************************************************************/ long nice_to_sec(tm) struct nice_time *tm; { long days_since_base; static int mdays[] = { 0, 0, 31, 31+28, 31+28+31, 31+28+31+30, 31+28+31+30+31, 31+28+31+30+31+30, 31+28+31+30+31+30+31, 31+28+31+30+31+30+31+31, 31+28+31+30+31+30+31+31+30, 31+28+31+30+31+30+31+31+30+31, 31+28+31+30+31+30+31+31+30+31+30 }; static int leapmdays[] = { 0, 0, 31, 31+29, 31+29+31, 31+29+31+30, 31+29+31+30+31, 31+29+31+30+31+30, 31+29+31+30+31+30+31, 31+29+31+30+31+30+31+31, 31+29+31+30+31+30+31+31+30, 31+29+31+30+31+30+31+31+30+31, 31+29+31+30+31+30+31+31+30+31+30 }; /* first compute number of days since January 1, 1978 */ days_since_base = (tm->year-1978) * 365L + (tm->year-1977)/4; if (tm->year%4 == 0) days_since_base += leapmdays[tm->month]; else days_since_base += mdays[tm->month]; days_since_base += tm->day-1; /* now the rest is easy */ return(days_since_base * (60L*60L*24L) + tm->hour * (60L*60L) + tm->minute * (60L) + tm->second); } /********************************************************************** * set_sys_time() -- set the system time * * Returns 0 normally, and -1 if an error occurs * **********************************************************************/ int set_sys_time(secs) long secs; { struct timerequest tr; if (OpenDevice (TIMERNAME, UNIT_VBLANK, &tr, 0L) != 0L) { printf("Clock error: can't open timer device\n"); return(-1); } tr.tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE; tr.tr_node.io_Message.mn_Node.ln_Pri = 0L; tr.tr_node.io_Message.mn_Node.ln_Name = NULL; tr.tr_node.io_Message.mn_ReplyPort = NULL; tr.tr_node.io_Command = TR_SETSYSTIME; tr.tr_time.tv_secs = secs; tr.tr_time.tv_micro = 0L; if (DoIO (&tr) != 0) { printf("Clock error: can't talk to timer device\n"); CloseDevice(&tr); return(-1); } CloseDevice (&tr); return(0); } /********************************************************************** * check_time() -- see if the given nice_time structure contains * * reasonable values; return 0 if so, -1 otherwise * **********************************************************************/ int check_time(tm) struct nice_time *tm; { #define WITHIN(val, lower, upper) ((lower<=val) & (val<=upper)) if (WITHIN(tm->year, 1978, 1999) && WITHIN(tm->month, 1, 12) && WITHIN(tm->day, 1, 31) && WITHIN(tm->day_of_week, 0, 6) && WITHIN(tm->hour, 0, 23) && WITHIN(tm->minute, 0, 59) && WITHIN(tm->second, 0, 59)) return(0); else return(-1); } /* * Variables for the clock routines */ struct Library *PotgoBase; /* points to Potgo Resource */ long potgo_bits; /* mask indicating which bits of the */ /* potgo resource we have allocated */ int held; /* 1 if the clock is currently stopped */ /********************************************************************** * init_port -- initialize the joystick port (right game port) so * * that we can talk to the clock * * Returns 0 normally, and -1 if an error occurs * **********************************************************************/ int init_port() { void pause(); /* open the Potgo resource so we can allocate ourselves the port */ PotgoBase = (struct Library *)OpenResource(POTGONAME); if (PotgoBase == NULL) { printf("Clock error: can't open Potgo resource\n"); return(-1); } /* ask for the output bits of the right game port */ potgo_bits = AllocPotBits(0xF000L); /* see if we got all the bits we asked for */ if (!((potgo_bits & 0x4000L) && (potgo_bits & 0x1000L))) { printf("Clock error: can't allocate gameport bits\n"); return(-1); } /* enable pins 5 and 9 for output, setting them both to 1 */ WritePotgo(0xF000L, 0xF000L); pause(); /* wait for lines to settle */ held = 0; /* indicate clock not being held */ return(0); } /********************************************************************** * term_port() -- release the game port * **********************************************************************/ void term_port() { /* set pins 5 and 9 back to input mode */ WritePotgo(0x0000L, 0xF000L); FreePotBits(potgo_bits); /* I would think we should close the resource here, but */ /* CloseResource() doesn't seem to exist */ } /********************************************************************** * set_sclk() -- set the "SCLK" line high, by bringing pin 5 of the * * game port low * **********************************************************************/ void set_sclk() { void pause(); WritePotgo(0x0000L, 0x1000L); pause(); } /********************************************************************** * clear_sclk() -- set the "SCLK" line low, by bringing pin 5 of * * the game port high * **********************************************************************/ void clear_sclk() { void pause(); WritePotgo(0x1000L, 0x1000L); pause(); } /********************************************************************** * set_sdata() -- set the "SDATA" line high, by bringing pin 9 of * * the game port low * **********************************************************************/ void set_sdata() { void pause(); WritePotgo(0x0000L, 0x4000L); pause(); } /********************************************************************** * clear_sdata() -- set the "SDATA" line low, by bringing pin 9 of * * the game port high * **********************************************************************/ void clear_sdata() { void pause(); WritePotgo(0x4000L, 0x4000L); pause(); } /********************************************************************** * pause() -- delay for enough time for the gameport output lines * * to settle. The RKM gives this time as 300 micro- * * seconds, so to be on the safe side this routine * * pauses for about 500 microseconds. * * This routine depends on the CPU being a 68000 running * * at 7.16 Mhz * **********************************************************************/ void pause() { int i; for (i=1; i<= 70; ++i) ; } /*********************************************************************** * send() -- send the given thirteen bits of data to the clock * * curcuit. The bits in the data word are * * * * A3 A2 A1 A0 RD WBE HOLD WR D3 D2 D1 D0=S1 S2 * * 12 11 10 9 8 7 6 5 4 3 2 1 0 * * (MSB) (LSB) * ***********************************************************************/ void send(d) int d; { int i; /* shift the bits into the shift register */ for (i=1; i<=13; ++i) { if ((d & 1) == 1) set_sdata(); else clear_sdata(); set_sclk(); /* strobe the bit in */ if (i<13) clear_sclk(); d >>= 1; } clear_sdata(); set_sdata(); /* latch the shift register contents */ clear_sclk(); } /********************************************************************** * write_reg() -- write the given value into the given register * **********************************************************************/ void write_reg(r,v) int r,v; { void send(); send(held<<6); send((r<<9) | 0x080 | (held<<6) | (v<<1)); send((r<<9) | 0x0a0 | (held<<6) | (v<<1)); send((r<<9) | 0x080 | (held<<6) | (v<<1)); send(held<<6); } /********************************************************************** * hold() -- stop the clock, and set the held flag so that the * * clock will remain held while register reads or writes * * are done * **********************************************************************/ void hold() { held = 1; send(0x040); } /********************************************************************** * no_hold() -- restart the clock if it was held * **********************************************************************/ void no_hold() { held = 0; send(0x000); } /********************************************************************** * set_time() -- set the clock * **********************************************************************/ void set_time(tm) struct nice_time *tm; { void hold(), nohold(), write_reg(); int leap_year, pm; leap_year = (tm->year%4 == 0); pm = (tm->hour >= 12); hold(); write_reg(12, (tm->year%100)/10); write_reg(11, tm->year%10); write_reg(10, tm->month/10); write_reg(9, tm->month%10); write_reg(8, (tm->day/10) | (leap_year<<2)); write_reg(7, tm->day%10); write_reg(6, tm->day_of_week); write_reg(5, (tm->hour/10) | (pm<<2) | 8); write_reg(4, tm->hour%10); write_reg(3, tm->minute/10); write_reg(2, tm->minute%10); write_reg(1, tm->second/10); write_reg(0, tm->second%10); no_hold(); } SHAR_EOF if test 14906 -ne "`wc -c < 'clockwr.c'`" then echo shar: error transmitting "'clockwr.c'" '(should have been 14906 characters)' fi fi # end of overwriting check echo shar: extracting "'clockrd.c'" '(13617 characters)' if test -f 'clockrd.c' then echo shar: will not over-write existing file "'clockrd.c'" else cat << \SHAR_EOF > 'clockrd.c' /********************************************************************** * clock.c -- read the time from the hardware clock, and set the * * software clock to match. If the -d option is given, * * the time is displayed as well. * **********************************************************************/ #include <stdio.h> #include <exec/types.h> #include <hardware/cia.h> #include <resources/potgo.h> #include <exec/nodes.h> #include <exec/lists.h> #include <devices/timer.h> #include <functions.h> #include "nice_time.h" /********************************************************************** * main program * **********************************************************************/ main(argc, argv) int argc; char *argv[]; { int dflag; struct nice_time tm; long seconds; void term_port(), get_time(), print_time(); int init_port(), set_sys_time(), check_time(); long nice_to_sec(); dflag = 0; if (argc == 2 && strcmp(argv[1], "-d") == 0) dflag = 1; if (init_port() != 0) exit(1); get_time(&tm); /* read the hardware clock */ term_port(); if (check_time(&tm) == -1) /* see if values reasonable */ { /* (if not, the clock is not */ /* set or not there) */ printf("Clock error: clock contents not valid\n"); exit(1); } if (dflag) print_time(&tm); seconds = nice_to_sec(&tm); /* convert time to seconds since */ /* the base date */ (void)set_sys_time(seconds); /* set the software clock */ } /* * Variables for the clock routine */ struct Library *PotgoBase; /* points to Potgo Resource */ long potgo_bits; /* mask indicating which bits of the */ /* potgo resource we have allocated */ int held; /* 1 if the clock is currently stopped */ /********************************************************************** * init_port -- initialize the joystick port (right game port) so * * that we can talk to the clock * * Returns 0 normally, and -1 if an error occurs * **********************************************************************/ int init_port() { void pause(); /* open the Potgo resource so we can allocate ourselves the port */ PotgoBase = (struct Library *)OpenResource(POTGONAME); if (PotgoBase == NULL) { printf("Clock error: can't open Potgo resource\n"); return(-1); } /* ask for the output bits of the right game port */ potgo_bits = AllocPotBits(0xF000L); /* see if we got all the bits we asked for */ if (!((potgo_bits & 0x4000L) && (potgo_bits & 0x1000L))) { printf("Clock error: can't allocate gameport bits\n"); return(-1); } /* enable pins 5 and 9 for output, setting them both to 1 */ WritePotgo(0xF000L, 0xF000L); pause(); /* wait for lines to settle */ held = 0; /* indicate clock not being held */ return(0); } /********************************************************************** * term_port() -- release the game port * **********************************************************************/ void term_port() { /* set pins 5 and 9 back to input mode */ WritePotgo(0x0000L, 0xF000L); FreePotBits(potgo_bits); /* I would think we should close the resource here, but */ /* CloseResource() doesn't seem to exist */ } /********************************************************************** * set_sclk() -- set the "SCLK" line high, by bringing pin 5 of the * * game port low * **********************************************************************/ void set_sclk() { void pause(); WritePotgo(0x0000L, 0x1000L); pause(); } /********************************************************************** * clear_sclk() -- set the "SCLK" line low, by bringing pin 5 of * * the game port high * **********************************************************************/ void clear_sclk() { void pause(); WritePotgo(0x1000L, 0x1000L); pause(); } /********************************************************************** * set_sdata() -- set the "SDATA" line high, by bringing pin 9 of * * the game port low * **********************************************************************/ void set_sdata() { void pause(); WritePotgo(0x0000L, 0x4000L); pause(); } /********************************************************************** * clear_sdata() -- set the "SDATA" line low, by bringing pin 9 of * * the game port high * **********************************************************************/ void clear_sdata() { void pause(); WritePotgo(0x4000L, 0x4000L); pause(); } /********************************************************************** * pause() -- delay for enough time for the gameport output lines * * to settle. The RKM gives this time as 300 micro- * * seconds, so to be on the safe side this routine * * pauses for about 500 microseconds. * * This routine depends on the CPU being a 68000 running * * at 7.16 Mhz * **********************************************************************/ void pause() { int i; for (i=1; i<= 70; ++i) ; } /*********************************************************************** * send() -- send the given thirteen bits of data to the clock * * curcuit. The bits in the data word are * * * * A3 A2 A1 A0 RD WBE HOLD WR D3 D2 D1 D0=S1 S2 * * 12 11 10 9 8 7 6 5 4 3 2 1 0 * * (MSB) (LSB) * ***********************************************************************/ void send(d) int d; { int i; /* shift the bits into the shift register */ for (i=1; i<=13; ++i) { if ((d & 1) == 1) set_sdata(); else clear_sdata(); set_sclk(); /* strobe the bit in */ if (i<13) clear_sclk(); d >>= 1; } clear_sdata(); set_sdata(); /* latch the shift register contents */ clear_sclk(); } /********************************************************************** * read_reg() -- read and return the contents of the given register * **********************************************************************/ int read_reg(r) int r; { int data, bit0, bit1, bit2, bit3, i; UWORD raw_data; void send(), set_sclk(), clear_sclk(); /* macro to read the state of pin 6 of the port */ /* (ciaa is a macro defined in <hardware/cia.h>) */ #define READBIT ((ciaa.ciapra & CIAF_GAMEPORT1) != 0) /* send the read command */ send((r<<9) | 0x10C | (held<<6)); /* read the data */ bit0 = READBIT; set_sclk(); clear_sclk(); bit1 = READBIT; set_sclk(); clear_sclk(); bit3 = READBIT; set_sclk(); clear_sclk(); bit2 = READBIT; data = (bit0 ) | (bit1 << 1) | (bit2 << 2) | (bit3 << 3); return(data); } /********************************************************************** * hold() -- stop the clock, and set the held flag so that the * * clock will remain held while register reads or writes * * are done * **********************************************************************/ void hold() { held = 1; send(0x040); } /********************************************************************** * no_hold() -- restart the clock if it was held * **********************************************************************/ void no_hold() { held = 0; send(0x000); } /********************************************************************** * get_time() -- read the time from the clock and place it in a * * nice_time structure. * **********************************************************************/ void get_time(tm) struct nice_time *tm; { void hold(), nohold(); int read_reg(); hold(); tm->year = 1900 + 10 * read_reg(12) + read_reg(11); tm->month = 10 * (read_reg(10)&1) + read_reg(9); tm->day = 10 * (read_reg(8)&3) + read_reg(7); tm->day_of_week = read_reg(6); tm->hour = 10 * (read_reg(5)&3) + read_reg(4); tm->minute = 10 * (read_reg(3)&7) + read_reg(2); tm->second = 10 * (read_reg(1)&7) + read_reg(0); no_hold(); } /********************************************************************** * print_time() -- display the contents of a nice_time structure * **********************************************************************/ void print_time(tm) struct nice_time *tm; { static char *mnames[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; static char *dnames[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; printf("%-9s %2d-%s-%02d %2d:%02d:%02d", dnames[tm->day_of_week], tm->day, mnames[tm->month-1], tm->year % 100, (tm->hour==0) ? 12 : (tm->hour<=12) ? tm->hour : tm->hour-12, tm->minute, tm->second); if (tm->hour < 12) printf(" AM\n"); else printf(" PM\n"); } /********************************************************************** * nice_to_sec() -- convert the given nice_time structure into * * seconds since 00:00:00 January 1, 1978 * **********************************************************************/ long nice_to_sec(tm) struct nice_time *tm; { long days_since_base; static int mdays[] = { 0, 0, 31, 31+28, 31+28+31, 31+28+31+30, 31+28+31+30+31, 31+28+31+30+31+30, 31+28+31+30+31+30+31, 31+28+31+30+31+30+31+31, 31+28+31+30+31+30+31+31+30, 31+28+31+30+31+30+31+31+30+31, 31+28+31+30+31+30+31+31+30+31+30 }; static int leapmdays[] = { 0, 0, 31, 31+29, 31+29+31, 31+29+31+30, 31+29+31+30+31, 31+29+31+30+31+30, 31+29+31+30+31+30+31, 31+29+31+30+31+30+31+31, 31+29+31+30+31+30+31+31+30, 31+29+31+30+31+30+31+31+30+31, 31+29+31+30+31+30+31+31+30+31+30 }; /* first compute number of days since January 1, 1978 */ days_since_base = (tm->year-1978) * 365L + (tm->year-1977)/4; if (tm->year%4 == 0) days_since_base += leapmdays[tm->month]; else days_since_base += mdays[tm->month]; days_since_base += tm->day-1; /* now the rest is easy */ return(days_since_base * (60L*60L*24L) + tm->hour * (60L*60L) + tm->minute * (60L) + tm->second); } /********************************************************************** * set_sys_time() -- set the system time * * Returns 0 normally, and -1 if an error occurs * **********************************************************************/ int set_sys_time(secs) long secs; { struct timerequest tr; if (OpenDevice (TIMERNAME, UNIT_VBLANK, &tr, 0L) != 0L) { printf("Clock error: can't open timer device\n"); return(-1); } tr.tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE; tr.tr_node.io_Message.mn_Node.ln_Pri = 0L; tr.tr_node.io_Message.mn_Node.ln_Name = NULL; tr.tr_node.io_Message.mn_ReplyPort = NULL; tr.tr_node.io_Command = TR_SETSYSTIME; tr.tr_time.tv_secs = secs; tr.tr_time.tv_micro = 0L; if (DoIO (&tr) != 0) { printf("Clock error: can't talk to timer device\n"); CloseDevice(&tr); return(-1); } CloseDevice (&tr); return(0); } /********************************************************************** * check_time() -- see if the given nice_time structure contains * * reasonable values; return 0 if so, -1 otherwise * **********************************************************************/ int check_time(tm) struct nice_time *tm; { #define WITHIN(val, lower, upper) ((lower<=val) & (val<=upper)) if (WITHIN(tm->year, 1978, 1999) && WITHIN(tm->month, 1, 12) && WITHIN(tm->day, 1, 31) && WITHIN(tm->day_of_week, 0, 6) && WITHIN(tm->hour, 0, 23) && WITHIN(tm->minute, 0, 59) && WITHIN(tm->second, 0, 59)) return(0); else return(-1); } SHAR_EOF if test 13617 -ne "`wc -c < 'clockrd.c'`" then echo shar: error transmitting "'clockrd.c'" '(should have been 13617 characters)' fi fi # end of overwriting check echo shar: extracting "'clocktest.c'" '(13473 characters)' if test -f 'clocktest.c' then echo shar: will not over-write existing file "'clocktest.c'" else cat << \SHAR_EOF > 'clocktest.c' #include <stdio.h> #include <exec/types.h> #include <hardware/custom.h> #include <hardware/cia.h> #include <resources/potgo.h> #include <functions.h> #include "nice_time.h" /********************************************************************** * Clock hardware testing program * * accepts the commands * * sd set the SDATA line high * * cd set the SDATA line low * * sc set the SCLK line high * * cc set the SCLK line low * * send num send and latch the given 13-bit value (num in hex) * * read reg read the indicated register (reg in hex) * * write r v write v into register r (r and v in hex) * * hold stop the clock * * nohold restart the clock * * get get and display the time * * set y m d dw h m s set the time * * e.g. set 1987 3 7 6 20 43 00 for Saturday March y, 1987 * * 8:43 PM * * quit exit the program * **********************************************************************/ main() { char buf[800]; int d, r; void getline(), term_port(), set_sclk(), set_sdata(), clear_sclk(), clear_sdata(), send(), write_reg(), hold(), no_hold(), get_time(), set_time(), print_time(); int init_port(), read_reg(); printf("Clock testing program\n"); if (init_port() != 0) exit(1); for (;;) { printf("Command: "); fflush(stdout); getline(buf); if (strcmp(buf, "quit") == 0) break; else if (strcmp(buf, "sd") == 0) set_sdata(); else if (strcmp(buf, "cd") == 0) clear_sdata(); else if (strcmp(buf, "sc") == 0) set_sclk(); else if (strcmp(buf, "cc") == 0) clear_sclk(); else if (strncmp(buf, "send", 4) == 0) { sscanf(buf+4, "%x", &d); send(d); } else if (strncmp(buf, "read", 4) == 0) { sscanf(buf+4, "%x", &r); d = read_reg(r); printf("Register %x contains %x\n", r, d); } else if (strncmp(buf, "write", 5) == 0) { sscanf(buf+5, "%x %x", &r, &d); write_reg(r,d); } else if (strcmp(buf, "hold") == 0) hold(); else if (strcmp(buf, "nohold") == 0) no_hold(); else if (strcmp(buf, "get") == 0) { struct nice_time tm; get_time(&tm); print_time(&tm); } else if (strncmp(buf, "set", 3) == 0) { struct nice_time tm; sscanf(buf+3, "%d %d %d %d %d %d %d", &tm.year, &tm.month, &tm.day, &tm.day_of_week, &tm.hour, &tm.minute, &tm.second); set_time(&tm); } else printf("Unknown comand\n"); } term_port(); } /********************************************************************** * getline() -- read a line from stdin * **********************************************************************/ void getline(buf) char *buf; { int ch; while ((ch = getchar()) != '\n' && ch != EOF) *buf++ = ch; *buf = '\0'; } /* * Variables for the clock routines */ struct Library *PotgoBase; /* points to Potgo Resource */ long potgo_bits; /* mask indicating which bits of the */ /* potgo resource we have allocated */ int held; /* 1 if the clock is currently stopped */ /********************************************************************** * init_port -- initialize the joystick port (right game port) so * * that we can talk to the clock * * Returns 0 normally, and -1 if an error occurs * **********************************************************************/ int init_port() { void pause(); /* open the Potgo resource so we can allocate ourselves the port */ PotgoBase = (struct Library *)OpenResource(POTGONAME); if (PotgoBase == NULL) { printf("Clock error: can't open Potgo resource\n"); return(-1); } /* ask for the output bits of the right game port */ potgo_bits = AllocPotBits(0xF000L); /* see if we got all the bits we asked for */ if (!((potgo_bits & 0x4000L) && (potgo_bits & 0x1000L))) { printf("Clock error: can't allocate gameport bits\n"); return(-1); } /* enable pins 5 and 9 for output, setting them both to 1 */ WritePotgo(0xF000L, 0xF000L); pause(); /* wait for lines to settle */ held = 0; /* indicate clock not being held */ return(0); } /********************************************************************** * term_port() -- release the game port * **********************************************************************/ void term_port() { /* set pins 5 and 9 back to input mode */ WritePotgo(0x0000L, 0xF000L); FreePotBits(potgo_bits); /* I would think we should close the resource here, but */ /* CloseResource() doesn't seem to exist */ } /********************************************************************** * set_sclk() -- set the "SCLK" line high, by bringing pin 5 of the * * game port low * **********************************************************************/ void set_sclk() { void pause(); WritePotgo(0x0000L, 0x1000L); pause(); } /********************************************************************** * clear_sclk() -- set the "SCLK" line low, by bringing pin 5 of * * the game port high * **********************************************************************/ void clear_sclk() { void pause(); WritePotgo(0x1000L, 0x1000L); pause(); } /********************************************************************** * set_sdata() -- set the "SDATA" line high, by bringing pin 9 of * * the game port low * **********************************************************************/ void set_sdata() { void pause(); WritePotgo(0x0000L, 0x4000L); pause(); } /********************************************************************** * clear_sdata() -- set the "SDATA" line low, by bringing pin 9 of * * the game port high * **********************************************************************/ void clear_sdata() { void pause(); WritePotgo(0x4000L, 0x4000L); pause(); } /********************************************************************** * pause() -- delay for enough time for the gameport output lines * * to settle. The RKM gives this time as 300 micro- * * seconds, so to be on the safe side this routine * * pauses for about 500 microseconds. * * This routine depends on the CPU being a 68000 running * * at 7.16 Mhz * **********************************************************************/ void pause() { int i; for (i=1; i<= 70; ++i) ; } /*********************************************************************** * send() -- send the given thirteen bits of data to the clock * * circuit. The bits in the data word are * * * * A3 A2 A1 A0 RD WBE HOLD WR D3 D2 D1 D0=S1 S2 * * 12 11 10 9 8 7 6 5 4 3 2 1 0 * * (MSB) (LSB) * ***********************************************************************/ void send(d) int d; { int i; /* shift the bits into the shift register */ for (i=1; i<=13; ++i) { if ((d & 1) == 1) set_sdata(); else clear_sdata(); set_sclk(); /* strobe the bit in */ if (i<13) clear_sclk(); d >>= 1; } clear_sdata(); set_sdata(); /* latch the shift register contents */ clear_sclk(); } /********************************************************************** * read_reg() -- read and return the contents of the given register * **********************************************************************/ int read_reg(r) int r; { int data, bit0, bit1, bit2, bit3, i; UWORD raw_data; void send(), set_sclk(), clear_sclk(); /* macro to read the state of pin 6 of the port */ /* (ciaa ia a macro defined in <hardware.cia.h>) */ #define READBIT ((ciaa.ciapra & CIAF_GAMEPORT1) != 0) /* send the read command */ send((r<<9) | 0x10C | (held<<6)); /* read the data */ bit0 = READBIT; set_sclk(); clear_sclk(); bit1 = READBIT; set_sclk(); clear_sclk(); bit3 = READBIT; set_sclk(); clear_sclk(); bit2 = READBIT; data = (bit0 ) | (bit1 << 1) | (bit2 << 2) | (bit3 << 3); return(data); } /********************************************************************** * write_reg() -- write the given value into the given register * **********************************************************************/ void write_reg(r,v) int r,v; { void send(); send(held<<6); send((r<<9) | 0x080 | (held<<6) | (v<<1)); send((r<<9) | 0x0a0 | (held<<6) | (v<<1)); send((r<<9) | 0x080 | (held<<6) | (v<<1)); send(held<<6); } /********************************************************************** * hold() -- stop the clock, and set the held flag so that the * * clock will remain held while register reads or writes * * are done * **********************************************************************/ void hold() { held = 1; send(0x040); } /********************************************************************** * no_hold() -- restart the clock if it was held * **********************************************************************/ void no_hold() { held = 0; send(0x000); } /********************************************************************** * get_time() -- read the time from the clock and place it in a * * nice_time structure. * **********************************************************************/ void get_time(tm) struct nice_time *tm; { void hold(), nohold(); int read_reg(); hold(); tm->year = 1900 + 10 * read_reg(12) + read_reg(11); tm->month = 10 * (read_reg(10)&1) + read_reg(9); tm->day = 10 * (read_reg(8)&3) + read_reg(7); tm->day_of_week = read_reg(6); tm->hour = 10 * (read_reg(5)&3) + read_reg(4); tm->minute = 10 * (read_reg(3)&7) + read_reg(2); tm->second = 10 * (read_reg(1)&7) + read_reg(0); no_hold(); } /********************************************************************** * print_time() -- display the contents of a nice_time structure * **********************************************************************/ void print_time(tm) struct nice_time *tm; { static char *mnames[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; static char *dnames[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; printf("%-9s %2d-%s-%02d %2d:%02d:%02d", dnames[tm->day_of_week], tm->day, mnames[tm->month-1], tm->year % 100, (tm->hour==0) ? 12 : (tm->hour<=12) ? tm->hour : tm->hour-12, tm->minute, tm->second); if (tm->hour < 12) printf(" AM\n"); else printf(" PM\n"); } /********************************************************************** * set_time() -- set the clock * **********************************************************************/ void set_time(tm) struct nice_time *tm; { void hold(), nohold(), write_reg(); int leap_year, pm; leap_year = (tm->year%4 == 0); pm = (tm->hour >= 12); hold(); write_reg(12, (tm->year%100)/10); write_reg(11, tm->year%10); write_reg(10, tm->month/10); write_reg(9, tm->month%10); write_reg(8, (tm->day/10) | (leap_year<<2)); write_reg(7, tm->day%10); write_reg(6, tm->day_of_week); write_reg(5, (tm->hour/10) | (pm<<2) | 8); write_reg(4, tm->hour%10); write_reg(3, tm->minute/10); write_reg(2, tm->minute%10); write_reg(1, tm->second/10); write_reg(0, tm->second%10); no_hold(); } SHAR_EOF if test 13473 -ne "`wc -c < 'clocktest.c'`" then echo shar: error transmitting "'clocktest.c'" '(should have been 13473 characters)' fi fi # end of overwriting check echo shar: extracting "'nice_time.h'" '(409 characters)' if test -f 'nice_time.h' then echo shar: will not over-write existing file "'nice_time.h'" else cat << \SHAR_EOF > 'nice_time.h' /* * nice_time.h -- a structure containing the time and date in a * convenient form */ struct nice_time { int year; /* e.g. 1986 */ int month; /* 1...12 */ int day; /* 1...31 */ int day_of_week; /* 0(Sun)...6(Sat) */ int hour; /* 0...23 */ int minute; /* 0...59 */ int second; /* 0...59 */ } ; SHAR_EOF if test 409 -ne "`wc -c < 'nice_time.h'`" then echo shar: error transmitting "'nice_time.h'" '(should have been 409 characters)' fi fi # end of overwriting check # End of shell archive exit 0