#platform "uLCD-32PT_GFX2"

// This program uses a Micromega uFPU coprocessor
// connected to the I2C port.

#inherit "4DGL_16bitColours.fnc"
#inherit "fops.inc"             //uFPU operation codes

#constant ICMODE 0      // leanest memory usage, slowest operation, seeks to each image. Adequate for most purposes.
//#constant ICMODE 1      // requires about 560 bytes for FAT buffer and disk structure, maps the cluster addresses, fastr than mode0.
//#constant ICMODE 2      // ultra fast raw mode, used in special circumstances where image refresh speed is important.

#constant FALSE, TRUE   // FALSE=0, TRUE=1
//-------------------- uM-FPU Register Definitions -----------------------------
#constant REGYEAR       10              // Year 32 bit
#constant REGMONTH      11              // Month 32 bit
#constant REGDAY        12              // Day 32 bit
#constant REGHOUR       13              // Hour 32 bit
#constant REGMINUTE     14              // Minute 32 bit
#constant REGSECOND     15              // Second 32 bit
#constant REGX          18              // X coordinate in pixels
#constant REGY          19              // Y coordinate in pixels
#constant REGMAG        20              // int Magnitude
#constant REGTEMP       21              // Temp 32 bit
#constant DJD           140             //Julian Date 64 bit
#constant DT            141             //T in centuries since 1900
#constant DSIDETIMEG    142             //Sidereal Time at Greenwich 0hrs GMT
#constant DREVOLUTIONS  143             //Sidereal Time in revolutions 0hrs GMT
#constant DREVRAD       144             //Sidereal Time in radians 0hrs GMT
#constant DSTATGACTUAL  145             //Sidereal Time in radians at current GMT
#constant DSTATLCACTUAL 146             //Sidereal Time in radians at local time in LC
#constant DRA           148             //RA of object in radians
#constant DDEC          149             //Dec of object in radians
#constant DALT          150             //altitude of object in radians
#constant DAZ           151             //azimuth of object in radians from S
#constant DMAG          154             //magnitude of object - signed
#constant REGSPECTRUM   17              //color - single character
#constant uFPU64        0xC8            // I2C address of uFPU64
#constant WR            1               // 0 write 1 read
#constant JD            1               // func 1 for Julian Date
#constant CalcT         2               // func 2 for T in centuries since 1/0/1900
#constant STat0hrs      3               // func 3 for sidereal time at 0 hrs for date at Greenwich
#constant STatGact      4               // func 4 for sidereal time at current time at Greenwich
#constant STatLoc       5               // func 5 for sidereal time at your location
#constant ScreenCoordinates 6           // func 6 for uLCD X, Y values
#constant Sun           7               // func 7 for Sun RA/Dec
#constant Moon          8               // func 8 for Moon RA/Dec
#constant Venus         9               // func 9 for Venus RA/DEC
#constant Mercury       10              // func 10 for MErcury RA/DEC
#constant Mars          11              // func 11 for Mars RA/DEC
#constant Jupiter       12              // func 12 for Jupiter RA/DEC
#constant Saturn        13              // func 13 for Saturn RA/DEC
// Global variables
var buffer[40];                         //buffer for incoming file data 2 char/word
var expbuffer[80];                      //expanded buffer 1 char/word
var msb;
var msb1;
var msb2;
var lsb;
var x, y;
func getlong(var address)
    I2C_Start();                                // Generate Start condition
    I2C_Write(uFPU64);                          // send slave address
    I2C_Write(LObyte(address));                 // Send register address
    I2C_Stop();                                 // generate a stop
    I2C_Start();                                // Generate start
    I2C_Write(uFPU64+WR);                       // send control byte for Read
    msb := I2C_Read();
    I2C_Ack();                                  //Acknowledge byte
    msb1 := I2C_Read();
    I2C_Ack();
    msb2 := I2C_Read();
    I2C_Ack();                                  //Acknowledge byte
    lsb := I2C_Read();
    I2C_Nack();                                 //last byte
    I2C_Stop();
    return;
endfunc
func bcd2bin(var binValue)                      // convert a 2 digit BCD value into its hex/binary single byte equivalent
    return (binValue>>4)*10 + (binValue&15);
endfunc
func readbyte(var address)                      // read a single byte from the required register on the uFPU64
    var b;
    I2C_Start();                                // Generate Start condition
    I2C_Write(uFPU64);                          // send slave address
    I2C_Write(LObyte(address));                 // Send register address
    I2C_Stop();                                 // generate a stop
    I2C_Start();                                // Generate start
    I2C_Write(uFPU64+WR);                       // send control byte for Read
    b := I2C_Read();                            // read the byte
    I2C_Nack();                                 // finished reading, send Not Ack
    I2C_Stop();                                 // Send Stop Condition
    return b;                                   // return the register value
endfunc
func writestring(var register, var command)                  // write the start of a string to the FPU
    I2C_Start();                                // Generate Start condition
    I2C_Write(uFPU64);                          // send slave address
    I2C_Write(register);                        // select the register
    I2C_Write(command);                         // write the command that is followed by a 0 terminated string
endfunc
func writebyte(var register, var value)         // write a single byte to the required register on the uFPU64
    I2C_Start();                                // Generate Start condition
    I2C_Write(uFPU64);                          // send slave address
    I2C_Write(register);                        // select the register
    I2C_Write(value);                           // save the value in selected register
    I2C_Stop();                                 // finished with bus
endfunc

func write2byte(var register, var value1, var value2)// write 2 bytes to the required register on the uFPU64
    I2C_Start();                                // Generate Start condition
    I2C_Write(uFPU64);                          // send slave address
    I2C_Write(register);                        // select the register
    I2C_Write(value1);                           // save the value in selected register
    I2C_Write(value2);                           // save the value in selected register
    I2C_Stop();                                 // finished with bus
endfunc
func write3byte(var register, var value1, var value2, var value3)// write 3 bytes to the required register uFPU64
    I2C_Start();                                // Generate Start condition
    I2C_Write(uFPU64);                          // send slave address
    I2C_Write(register);                        // select the register
    I2C_Write(value1);                           // save the value in selected register
    I2C_Write(value2);                           // save the value in selected register
    I2C_Write(value3);                           // save the value in selected register
    I2C_Stop();                                 // finished with bus
endfunc
func printstring()                              // print the string pointed to by the 0 reg uFPU64
    var     c;
    var     ccount;
    writebyte(0,READSTR);
    I2C_Start();                                // Generate Start condition
    I2C_Write(uFPU64);                          // send slave address
    I2C_Write(0);                               // Send register address
    I2C_Stop();
    I2C_Start();                                // Generate start
    I2C_Write(uFPU64+WR);                       // send control byte for Read
    pause(2);
    c:=0x31;                                    // set c == a non-zero value
    ccount := 20;                               // max length 20 bytes
    while(c!=0)
         c:=I2C_Read();
         if(c==0)                               // end of string if c == 0
            I2C_Nack();                         // signal last byte read
            break;                              // exit read loop
         endif
         I2C_Ack();                             // signal read success

         pause(10);
         print([CHR] c);                        // print on uLCD screen
    wend
    I2C_Stop();                                 // Send Stop Condition
endfunc
func expandbuffer()                             // expand incoming data to 1 char/word
var i, j;
    for (i:=0; i<40; i++)
        j:= 2*i;
        expbuffer[j] := buffer[i]&0xFF;
        j++;
        expbuffer[j] := buffer[i]>>8;
    next
endfunc


func    get_XY()
    write2byte(0,FCALL,ScreenCoordinates);  //get X and Y for Object
    write2byte(0,SELECTA,REGX);     //get X
    pause(10);
    writebyte(0,LREADA);             //get uFPU to send a 16 bit value
    pause(10);
    getlong(0);                         //get msb and lsb of X
    pause(10);
    x := msb2<<8;
    x:= x+lsb;
    write2byte(0,SELECTA,REGY);     //get Y
    writebyte(0,LREADA);             //get uFPU to send a 16 bit value
    pause(10);
    getlong(0);                      //get msb and lsb of Y
    y := msb2<<8;
    y:=y+lsb;
endfunc
func    main()
    var star_file;                              // handle for star data file
    var count;                                  // number of bytes in current line
    var c, i, j;
    var last;                                   //pointer to first char in naxt field
    var Action;
    var color;                                  //color of object
    var mag;                              //data required for plotting the object
    var state;
    var exit;
    var retry := 10;
    while(retry-- && !file_Mount());                                // mount the drive
    if (!retry)
        putstr("Mount Failed!");
        pause(2000);
        return;                                                     // exit if can't mount
    endif
    //open the star data file for reading
    star_file := file_Open("hyg11.txt",'r');
    if(file_Error())
        putstr("cannot open star data file");
        pause(5000);
        return;
    endif
    exit := 0;
    gfx_ScreenMode(LANDSCAPE);
    //I2C_Open(I2C_SLOW);                                             // 100khz
    I2C_Open(I2C_MED);                                            // 400khz
    //I2C_Open(I2C_FAST);                                           // 1mhz NB uFPU64 may not run at 1mhz!!!

    pause(10);
    writebyte(1,0);                             // reset the uFPU by writing a 0 to register 1
    pause(50);                                  // wait for the FPU64 to complete the reset
// send a SYNC commnad
    writebyte(0,SYNC);                          // make sure syncronization is in place
    c:=readbyte(0);                             // should be 0x5C
    txt_FontID(FONT1);
    txt_MoveCursor(2,3);
    txt_FGcolour(WHITE);
    print("Sync byte returned = ", [HEX2] c);
    pause(500);
// try getting version next
    print("\r\nVersion = ");
    writebyte(0,VERSION);
    printstring();
    print("\r\n");
    pause(500);
    Action := READ_TIME + FPUSTR;
    write2byte(0,RTC,Action);                   // read the date and time as a string
    writebyte(0,READSTR);                       // print the string
    printstring();
    pause(1000);
    touch_Set(TOUCH_ENABLE);                    // enable the touch screen
    gfx_Cls();
  while(!exit)                                                    // stay in loop til quit button hit
// get Julian Date and print it
    Action := START;
    write2byte(0,RTC,Action);                   // start the RTC
    write2byte(0,FCALL,JD);
    write2byte(0,FCALL,CalcT);
    write2byte(0,FCALL,STat0hrs);
    write2byte(0,FCALL,STatGact);
    write2byte(0,FCALL,STatLoc);
    write2byte(0,FCALL,ScreenCoordinates);
    gfx_Cls();

    gfx_ClipWindow(0,0,319,75);
    gfx_Clipping(ON);
    gfx_Circle(159, -171, 230, DARKOLIVEGREEN);//+60 ALT
    gfx_Clipping(OFF);
    gfx_ClipWindow(0,0,319,180);
    gfx_Clipping(ON);
    gfx_Circle(159, -465, 614, DARKOLIVEGREEN);//+30 ALT
    gfx_Clipping(OFF);
    gfx_ClipWindow(159,0,319,239);
    gfx_Clipping(ON);
    gfx_Circle(-240, 239, 490, DARKOLIVEGREEN);//+30 AZ
    gfx_Clipping(OFF);
    gfx_ClipWindow(159,0,319,239);
    gfx_Clipping(ON);
    gfx_Circle(19, 239, 318, DARKOLIVEGREEN);//+60 AZ
    gfx_Clipping(OFF);
    gfx_ClipWindow(0,0,159,239);
    gfx_Clipping(ON);
    gfx_Circle(559, 239, 490, DARKOLIVEGREEN);//-30 AZ
    gfx_Clipping(OFF);
    gfx_ClipWindow(0,0,159,239);
    gfx_Clipping(ON);
    gfx_Circle(300, 239, 318, DARKOLIVEGREEN);//-60 AZ
    gfx_Clipping(OFF);
    gfx_Vline(159,0,239,DARKOLIVEGREEN); // 0 AZ
    j:=0;
    // loop to process star data from uSD card
    while (!file_Error())
        count := file_GetS(buffer, 80, star_file); //get next line of star data
        expandbuffer();
        i:=0;
        while(expbuffer[i] != ',')
            i++;
        wend
    // when loop exits i points to ','
        last := i++;                        //first character of RA field
        // send command to process RA field
        write2byte(0,SELECTA,DRA);
        writestring(0,ATOF);                //converts string to reg 0
        while (expbuffer[i] != ',')
            I2C_Write(expbuffer[i]);
            i++;
        wend
        I2C_Write(0x00);                    //send 0x00 to terminate string
        I2C_Stop();                         //finished transferring RA to uFPU

    writebyte(0,LSET0);
    write2byte(0,FTOA,0);
    // when loop exits i points to ','
        last := i++;                        //first character of Dec field
        // send command to process DEC field
        write2byte(0,SELECTA,DDEC);
        writestring(0,ATOF);                //converts string to reg 0
        while (expbuffer[i] != ',')
            I2C_Write(expbuffer[i]);
            i++;
        wend
        I2C_Write(0x00);                    //send 0x00 to terminate string
        I2C_Stop();                         //finished transferring RA to uFPU

    writebyte(0,LSET0);
     // when loop exits i points to ','
        last := i++;                        //first character of Mag field
        // send command to process Mag field
        write2byte(0,SELECTA,DMAG);
         writestring(0,ATOF);                //converts string to reg 0
        while (expbuffer[i] != ',')
            I2C_Write(expbuffer[i]);
            i++;
        wend
        I2C_Write(0x00);                    //send 0x00 to terminate string
        I2C_Stop();                         //finished transferring RA to uFPU

    writebyte(0,LSET0);
     // when loop exits i points to ','
        last := i++;                        //first character of Spectrum field
        last++;
        // determine color based on first character of Spectrum
    if (expbuffer[last] == 'A')         //blue-white
        color := WHITE;
    endif
    if (expbuffer[last] == 'B')         //blue
        color := BLUE;
    endif
    if (expbuffer[last] == 'F')         //white
        color := YELLOW;
    endif
    if (expbuffer[last] == 'G')         //yellow
        color := YELLOW;
    endif
    if (expbuffer[last] == 'K')         //orange
        color := ORANGE;
    endif
    if (expbuffer[last] == 'M')         //red
        color := RED;
    endif
    if (expbuffer[last] == 'O')
        color := BLUE;                  //bright blue
    endif
    if (expbuffer[last] == 'W')         //white
        color := WHITE;
    endif
    if (expbuffer[last] == 'S')

        get_XY();
        gfx_MoveTo(x,y);              //start a constellation line
    endif
    if ((expbuffer[last] == 'N')||(expbuffer[last] == 'E'))
        get_XY();
        gfx_Set(OBJECT_COLOUR, 0x0204);
        gfx_LineTo(x,y);            //continue a constellation line
    endif

    gfx_Set(OBJECT_COLOUR, color);
    j++;
    // need to read X, Y and MAG from the uFPU
    // Y is 16 bits so read a word
    get_XY();
    write2byte(0,SELECTA,REGMAG);     //get MAG
    writebyte(0,LREADA);             //get uFPU to send a 16 bit value
    getlong(0);                      //get msb and lsb of MAG
    pause(10);

    mag := msb2<<8;
    mag:=mag+lsb;
    if((x >= 0 && x <= 319) &&(y >= 0 && y <= 239))
    //visible print a dot
        if(mag == 5)
            gfx_MoveTo(x,y);
            gfx_Bullet(2);
        endif
        if(mag == 4)
            gfx_MoveTo(x,y);
            gfx_Bullet(1);
        endif
        gfx_PutPixel(x,y,color);
    endif
    state := touch_Get(TOUCH_STATUS);                           // we'll look for any touch activity
    if(state ==  TOUCH_RELEASED)                                // if there's a release;
        exit := 1;
    endif
    wend
    file_Close(star_file);

//open the star data file for reading
    star_file := file_Open("hyg11.txt",'r');
    if(file_Error())
        putstr("cannot open star data file");
        pause(5000);
        return;
    endif
    write2byte(0,FCALL,Sun);  //get RA and Dec of Sum
    get_XY();
    if((x >= 0 && x <= 319) &&(y >= 0 && y <= 239))
        gfx_Set(OBJECT_COLOUR, YELLOW);
        gfx_MoveTo(x,y);
        gfx_Bullet(4);
        gfx_MoveTo(x+5,y+5);
        print("sun");
    endif
    write2byte(0,FCALL,Moon);  //get RA and Dec of Moon
    get_XY();
    if((x >= 0 && x <= 319) &&(y >= 0 && y <= 239))
        gfx_Set(OBJECT_COLOUR, LIGHTGREY);
        gfx_MoveTo(x,y);
        gfx_Bullet(4);
        gfx_MoveTo(x+4,y+4);
        print("moon");
    endif
    write2byte(0,FCALL,Venus);  //get RA and Dec of Venus
    get_XY();
    if((x >= 0 && x <= 319) &&(y >= 0 && y <= 239))
        gfx_Set(OBJECT_COLOUR, LIGHTGREY);
        gfx_MoveTo(x,y);
        gfx_Bullet(3);
        gfx_MoveTo(x+4,y+4);
        print("venus");
    endif
    write2byte(0,FCALL,Mercury);  //get RA and Dec of Mercury
    get_XY();
    if((x >= 0 && x <= 319) &&(y >= 0 && y <= 239))
        gfx_Set(OBJECT_COLOUR, LIGHTGREY);
        gfx_MoveTo(x,y);
        gfx_Bullet(3);
        gfx_MoveTo(x+4,y+4);
        print("mercury");
    endif
    write2byte(0,FCALL,Mars);  //get RA and Dec of Mars
    get_XY();
    if((x >= 0 && x <= 319) &&(y >= 0 && y <= 239))
        gfx_Set(OBJECT_COLOUR, RED);
        gfx_MoveTo(x,y);
        gfx_Bullet(3);
        gfx_MoveTo(x+4,y+4);
        print("mars");
    endif
    write2byte(0,FCALL,Jupiter);  //get RA and Dec of Jupiter
   get_XY();
    if((x >= 0 && x <= 319) &&(y >= 0 && y <= 239))
        gfx_Set(OBJECT_COLOUR, YELLOW);
        gfx_MoveTo(x,y);
        gfx_Bullet(3);
        gfx_MoveTo(x+4,y+4);
        print("jupiter");
    endif

    write2byte(0,FCALL,Saturn);  //get RA and Dec of Saturn
    get_XY();
    if((x >= 0 && x <= 319) &&(y >= 0 && y <= 239))
        gfx_Set(OBJECT_COLOUR, YELLOW);
        gfx_MoveTo(x,y);
        gfx_Bullet(3);
        gfx_Ellipse(x,y,6,2,YELLOW);    //Saturn rings
        gfx_MoveTo(x+4,y+4);
        print("saturn");
    endif

    pause(60000);       //delay 1 minute before next update of screen
  wend
  gfx_ScreenMode(PORTRAIT);
endfunc
