--- moonrock.c 2009-12-28 04:26:47.000000000 +0100 +++ moonrock_07.c 2009-12-31 18:52:24.000000000 +0100 @@ -12,6 +12,9 @@ * (original upload 5 November 2007 by Tomruen) * moon phase code based on moontool.c by John Walker * + * Extended by: Marek Niemiec, DB1BMN, Dec. 29-31 th. 2009 + * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -103,11 +106,9 @@ series of lunations (1923 January 16) */ /* Properties of the Earth */ - #define EARTHRAD 6378.16 /* Radius of Earth in kilometres */ /* Handy mathematical functions */ - #define PI 3.14159265358979323846 #define SGN(x) (((x) < 0) ? -1 : ((x) > 0 ? 1 : 0)) /* Extract sign */ @@ -301,31 +302,239 @@ return FIXANGLE(MoonAge) / 360.0; } +/* convert from julian time to tm struct time */ +struct tm julian_2_tm(double julian_time) +{ + // http://de.wikipedia.org/wiki/Julianisches_Datum + + struct tm tmp; + rb->memcpy( &tmp, rb->get_time(), sizeof(struct tm)); // initialize by system time + + int Z; + double F; + double JD_plus_half = julian_time + 0.5; + int g, A, B, C, D, E; + double day; + int month, year; + double hour, minute, second; + + // apply conversion from julian to tm struct date and time + Z = (int)JD_plus_half; + F = JD_plus_half - (double)Z; + if (Z < 2299161) + { + //julian calendar + A = Z; + } + else + { + // gregorian calendar + g = (int)(((double)Z - 1867216.25) / 36524.25); + A = Z + 1 + g - (int)(g/4); + } + + B = A + 1524; + C = (int)(((double)B-122.1) / 365.25); + D = (int)(365.25 * (double)C); + E = (int)((double)(B-D) / 30.6001); + + day = (double)B - (double)D - (int)(30.6001 * (double)E) + F; // day inclusive fraction + + /* calculate Date */ + // month + if (E < 14) + { + month = E - 1 ; + } + else + { + month = E - 13; + } + + // year + if (month > 2) + { + year = C - 4716; + } + else + { + year = C - 4715; + } + + /* calculate Time */ + hour = (day - (int)day) * 24; + minute = (hour - (int)hour) * 60; + second = (minute - (int)minute) * 60; + + + // write results to struct + tmp.tm_year = year - 1900; + tmp.tm_mon = month; + tmp.tm_mday = day; + tmp.tm_hour = (int)hour; + tmp.tm_min = (int)minute; + tmp.tm_sec = (int)second; + + return tmp; +} + + +/* convert local time to UTC */ +struct tm local_2_utc(struct tm *local, double utc_offset_hours) +{ + struct tm tmp; // temporary time struct to opernate on + double julian_time; + double utc_offset_seconds; + double utc_offset_julian; + + utc_offset_seconds = utc_offset_hours * 3600; // 3600 seconds per hour + utc_offset_julian = utc_offset_seconds / 86400; // 86400 seconds per day + + // convert tm struct time to absolute julian date + julian_time = jtime(local); + julian_time = julian_time - utc_offset_julian; // shift by UTC offset + + // NOTE: the week-day is not shifted so far! + + // convert back to tm struct from julian time format + tmp = julian_2_tm(julian_time); + + return tmp; + //return *local; // dummy output +} + +/* calculate easter date */ +struct tm easter_date(int X) +{ + // modified algorithm by Heiner Lichtenberg (1997) + // http://de.wikipedia.org/wiki/Osterformel + // + // X is the input year + + struct tm tmp; + rb->memcpy( &tmp, rb->get_time(), sizeof(struct tm)); // initialize by system time + + int K; // scularity number + int M; // seculary moonshift + int S; // seculary sunshift + int A; // moon parameter + int D; // first full moon in spring + int R; // calendar correction + int OG; // easter limit + int SZ; // first sunday in march + int OE; // easter distance + int OS; // easter sunday date in March (32. March == 1. April etc.) + int month=3, day; + + // calculate + K = (int)((double)X / 100.0); + M = (int)( (15.0+((3.0 * (double)K + 3.0) / 4.0)) - ( ( 8.0 * (double)K + 13.0) / 25.0) ); + S = (int)( 2.0 - ( (3.0 * (double)K + 3.0 ) / 4.0) ); + A = X % 19; + D = (19*A + M) % 30; + R = (int)((double)D / 29.0) + (int)( (int)((double)D / 28.0) - (int)((double)D / 29.0 )) * (int)((double)A / 11.0); + OG = 21 + D - R; + SZ = 7 - (X + S + (int)((double)X / 4.0)) % 7; + OE = 7 - (OG - SZ) % 7; + OS = OG + OE; + + if (OS > 31) + { + month = 4; + day = OS - 31; + } + else + { + day = OS; + } + + // write results to struct + tmp.tm_year = X - 1900; + tmp.tm_mon = month; + tmp.tm_mday = day; + + return tmp; +} + /* this is the plugin entry point */ enum plugin_status plugin_start(const void* parameter) { (void)parameter; - struct tm tm,tm1; + struct tm tm,tm1, tm_utc, tm_easter_now, tm_easter_next; int font_w,font_h,iphase,action; - double phase,jd,cphase, aom, cdist, cangdia, csund, csuang; - bool viewbmp=true; + double phase; + double jd; /* Date for which to calculate phase */ + double cphase; /* Illuminated fraction */ + double aom; /* Age of moon in days */ + double cdist; /* Distance in kilometres */ + double cangdia; /* Angular diameter in degrees */ + double csund; /* Distance to Sun */ + double csuang; /* Sun's angular diameter */ + double utc_offset = 1; // utc offset in hours, eastern from greenwich: positive, western from greenwich: negative + //bool viewbmp=true; bool refresh=true; bool done=false; bool getaction; + + int current_page = 1; /* starting page */ + #if defined(HAVE_LCD_BITMAP) && LCD_DEPTH>1 int ret,fd; static struct bitmap input_bmp; + #define num_pages 4 /* one more page for the moon picture */ + current_page--; +#else + #define num_pages 3 /* only two pages, because no picture to be displayed */ #endif - char output[20]; - static const char *desc[] = { - "new moon", "waxing crescent", - "first quarter","waxing gibbous", - "full moon","waning gibbous","last quarter", - "waning crescent" - }; - - rb->memcpy( &tm, rb->get_time(), sizeof(struct tm)); + char output[32]; /* output string buffer */ + + /* array with moon phase names */ + /* can we take also other languages into account? */ + static const char *desc[] = { + "new moon", + "waxing crescent", + "first quarter", + "waxing gibbous", + "full moon", + "waning gibbous", + "last quarter", + "waning crescent" + }; + + /* array with week day name abbreviations */ + /* guess there is already somwhere a function which returns it, even in different languages */ + static const char *wday_name[] = { + "Mo", + "Tu", + "We", + "Th", + "Fr", + "Sa", + "Su" + }; + + /* array with month names */ + static const char *month_name[] = { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" + }; + + rb->memcpy( &tm, rb->get_time(), sizeof(struct tm)); // get system time + /* convert from local time to utc */ + tm_utc = local_2_utc(&tm, utc_offset); + + #if defined(HAVE_LCD_BITMAP) && LCD_DEPTH>1 input_bmp.width = PICSIZE; input_bmp.height = PICSIZE; @@ -337,83 +546,203 @@ while(!done) { -#if LCD_DEPTH>=2 + #if LCD_DEPTH>=2 rb->lcd_set_backdrop(NULL); rb->lcd_set_background(LCD_BLACK); rb->lcd_set_foreground(LCD_WHITE); -#endif + #endif rb->lcd_clear_display(); - jd=jtime(&tm); + + + /* caculate moon infos */ + jd=jtime(&tm); phase=moon_phase(jd, &cphase, &aom, &cdist, &cangdia, &csund, &csuang); + + /* which page to display? */ + switch(current_page) + { + case 0: + /* show the moon picture */ + // ADD MORE CODE HERE + /* + rb->snprintf(output,sizeof(output), "Page 1"); + rb->lcd_puts(0,0,output); + */ + + if (fd>=0) + { + /* display moon opened picture */ + /* + rb->snprintf(output,sizeof(output), "Successfull open moonrock.dat"); + rb->lcd_puts(0,0,output); + */ + rb->lcd_getstringsize( (unsigned char *) "Calculating..", &font_w, &font_h); + rb->lcd_putsxy((LCD_WIDTH/2) - (font_w)/2, LCD_HEIGHT/2-font_h/2, + (unsigned char *) "Calculating.."); + rb->lcd_update(); + + if(refresh) + { + iphase=get_frame_no(phase); + rb->lseek(fd, (off_t) (iphase*BMPSKIP),SEEK_SET); + ret = scaled_read_bmp_fd(fd, &input_bmp, sizeof(bmp_buf), + FORMAT_NATIVE|FORMAT_RESIZE|FORMAT_KEEP_ASPECT, + NULL); + + if (ret < 0) + { + rb->splash(HZ, "Could not read bmp"); + return PLUGIN_ERROR; + } + + refresh=false; + } + + rb->lcd_bitmap(bmp_buf, + MAX(0,(LCD_WIDTH-input_bmp.width)/2), + MAX(0,(LCD_HEIGHT-input_bmp.height)/2), + input_bmp.width,input_bmp.height); + } + else + { + /* print some kind of error message or perhaps some ASCII-Art? */ + rb->snprintf(output,sizeof(output), "Error opening moonrock.dat"); + rb->lcd_puts(0,0,output); + } + + break; + // + case 1: + /* show the most important infos */ + // ADD .... + /* + rb->snprintf(output,sizeof(output), "Page 2"); + rb->lcd_puts(0,0,output); + */ + rb->lcd_clear_display(); + + + /* get current local time */ + rb->memcpy( &tm, rb->get_time(), sizeof(struct tm)); + /* convert from local time to utc */ + tm_utc = local_2_utc(&tm, utc_offset); + + /* caculate moon infos */ + //jd=jtime(&tm); + //phase=moon_phase(jd, &cphase, &aom, &cdist, &cangdia, &csund, &csuang); + + iphase=8*phase+0.5; + iphase=iphase%8; + + rb->snprintf(output,sizeof(output), "UTC: %02d:%02d:%02d %+2.1fh", tm_utc.tm_hour, tm_utc.tm_min, tm_utc.tm_sec, utc_offset ); /* some dummy output */ + rb->lcd_puts(0, 0,output); + rb->snprintf(output,sizeof(output), "%s. %02d. %s. %4d", wday_name[tm_utc.tm_wday-1], tm_utc.tm_mday, month_name[tm_utc.tm_mon-1], tm_utc.tm_year+1900); + rb->lcd_puts(0, 1,output); + + rb->snprintf(output,sizeof(output), "Age of Moon: %2d d", (int)(aom)); + rb->lcd_puts(0, 2,output); + rb->snprintf(output,sizeof(output), "Moon Phase: %3d%%", (int)(cphase*100+0.5)); + rb->lcd_puts(0, 3,output); + rb->snprintf(output,sizeof(output), "%s", desc[iphase]); + rb->lcd_puts(0, 4,output); + rb->snprintf(output,sizeof(output), "Lunation (B/2k): ####"); + rb->lcd_puts(0, 5,output); + + rb->lcd_puts(0,6, "Full Moon: hh:mm"); + rb->lcd_puts(0,7, "DD., dd.mm.yyyy UTC"); + + rb->lcd_puts(0,9, "New Moon: hh:mm"); + rb->lcd_puts(0,10, "DD., dd.mm.yyyy UTC"); + + + rb->lcd_update(); // do not forget to update the display! + + + break; + // + case 2: + /* show some additional infos */ + //.. + /* + rb->snprintf(output,sizeof(output), "Page 3"); + rb->lcd_puts(0,0,output); + */ + + + /* calculate easter date */ + tm_easter_now = easter_date(tm_utc.tm_year+1900); + tm_easter_next = easter_date(tm_utc.tm_year+1900+1); + + rb->snprintf(output,sizeof(output), "Julian Date:" ); + rb->lcd_puts(0, 0,output); + rb->snprintf(output,sizeof(output), "%f", jd ); + rb->lcd_puts(0, 1,output); + rb->snprintf(output,sizeof(output), "Moon's distance:"); + rb->lcd_puts(0, 2,output); + rb->snprintf(output,sizeof(output), "%.1f km", cdist); + rb->lcd_puts(0, 3,output); + rb->snprintf(output,sizeof(output), "* Apogee/Perigee? *"); // how do we calculate this? + rb->lcd_puts(0, 4,output); + + rb-snprintf(output,sizeof(output), "Easter Sunday:"); + rb->lcd_puts(0, 8,output); + rb-snprintf(output,sizeof(output), "%02d. %s. %4d", tm_easter_now.tm_mday, month_name[tm_easter_now.tm_mon-1], tm_easter_now.tm_year+1900); // current year + rb->lcd_puts(0, 9,output); + rb-snprintf(output,sizeof(output), "%02d. %s. %4d", tm_easter_next.tm_mday, month_name[tm_easter_next.tm_mon-1], tm_easter_next.tm_year+1900); // next year + rb->lcd_puts(0, 10,output); + + + rb->lcd_update(); // do not forget to update the display! + break; + case 3: + /* even more infos */ + rb->lcd_puts(0,0, "Rise: hh:mm"); + rb->lcd_puts(0,1, "DD., dd.mm.yyyy UTC"); + + rb->lcd_puts(0,3, "Set: hh:mm"); + rb->lcd_puts(0,4, "DD., dd.mm.yyyy UTC"); + + rb->lcd_puts(0,6, "Azimuth: ###"); + rb->lcd_puts(0,7, "Elevation: ##"); + + rb->lcd_puts(0,8, "Rect. ##:##:##"); + rb->lcd_puts(0,9, "Decl. ##:##:##"); + + rb->lcd_puts(0,10, "Zenit: hh:mm"); + + rb->lcd_update(); // do not forget to update the display! + break; + default: + break; + } + + rb->lcd_update(); /* refresh screen */ - /* it is too ugly on monochrome... */ -#if defined(HAVE_LCD_BITMAP) && LCD_DEPTH>1 - if(fd>=0 && viewbmp) - { - rb->lcd_getstringsize( (unsigned char *) "Calculating..", &font_w, &font_h); - rb->lcd_putsxy((LCD_WIDTH/2) - (font_w)/2, LCD_HEIGHT/2-font_h/2, - (unsigned char *) "Calculating.."); - rb->lcd_update(); - - if(refresh) - { - iphase=get_frame_no(phase); - rb->lseek(fd, (off_t) (iphase*BMPSKIP),SEEK_SET); - ret = scaled_read_bmp_fd(fd, &input_bmp, sizeof(bmp_buf), - FORMAT_NATIVE|FORMAT_RESIZE|FORMAT_KEEP_ASPECT, - NULL); - - if (ret < 0) - { - rb->splash(HZ, "Could not read bmp"); - return PLUGIN_ERROR; - } - - refresh=false; - } - - rb->lcd_bitmap(bmp_buf, - MAX(0,(LCD_WIDTH-input_bmp.width)/2), - MAX(0,(LCD_HEIGHT-input_bmp.height)/2), - input_bmp.width,input_bmp.height); - - } else -#endif - { - rb->lcd_clear_display(); - iphase=8*phase+0.5; - iphase=iphase%8; - rb->snprintf(output,sizeof(output),"%s", desc[iphase]); - - rb->lcd_getstringsize(output, &font_w, &font_h); - rb->lcd_putsxy((LCD_WIDTH/2) - (font_w)/2, LCD_HEIGHT/2-font_h, - (unsigned char *) output); - - rb->snprintf(output,sizeof(output),"(%d%% illuminated)", - (int)(cphase*100+0.5)); - - rb->lcd_getstringsize(output, &font_w, &font_h); - rb->lcd_putsxy((LCD_WIDTH/2) - (font_w)/2, LCD_HEIGHT/2+1, - (unsigned char *) output); - } - - rb->lcd_update(); - - getaction = false; + /* check for buttons */ + getaction = false; while(!getaction) { action = pluginlib_getaction(TIMEOUT_BLOCK, plugin_contexts, 1); switch(action) { - case QUIT_ACTION: + case QUIT_ACTION: /* leave applications */ done=true; getaction = true; break; - case TOGGLE_VIEW_ACTION: - viewbmp=!viewbmp; + case TOGGLE_VIEW_ACTION: /* jump to next page */ + current_page++; // add one + if (current_page == num_pages) + { + // start with first page again + #if defined(HAVE_LCD_BITMAP) && LCD_DEPTH>1 + current_page = 0; // first page shows thee picture + #else + current_page = 1; // only text output + #endif + } getaction = true; break; - case DATE_ACTION: + case DATE_ACTION: /* call date input form */ rb->memcpy( &tm1, &tm, sizeof(struct tm)); rb->set_time_screen((char*) "Moonrock date/time (GMT)" ,&tm1); if(tm1.tm_year != -1)