It is currently Wed Jul 06, 2011 7:24 pm

All times are UTC - 8 hours




 Page 1 of 1 [ 19 posts ] 
Author Message
 Post subject: Analog Clock
PostPosted: Mon Mar 07, 2011 1:20 pm 

Joined: Tue Feb 15, 2011 10:35 pm
Posts: 42
Made a simple analog clock using single pixel width anti-aliased lines. Click the button to animate the time and to wake up from sleep mode.

Video: http://www.youtube.com/watch?v=3NkpMplc1lU&feature=youtube_gdata

/**
* Simple Analog Clock
*
* Description:
* Draws an analog clock using the watch's native graphics. Single pixel thick anti-aliased
* lines are drawn using Xiaolin Wu's algorithm. The processor will go to sleep in 15 seconds
* if there is no activity. Clicking the button will animate the time.
*
*
* Copyright (C) 2011, Allerta Inc.
* Author: Ryan Young ([email protected])
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
* OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
* WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
**/

#include <pulse_os.h>
#include <pulse_types.h>

#include <stdint.h>

#define SLEEP_TIMEOUT 15000

uint8_t current_min;

uint8_t current_hour;

struct pulse_time_tm current_time;

uint32_t sleep_timer = -1;

color24_t hand_color = {113, 217, 226, 0};

color24_t tick_color = {0, 123, 167, 0};

typedef struct point
{
  uint8_t x;
  uint8_t y;
} point;

point center = {47, 63};

point Rtick[] =
{
    {46, 16}, {48, 16}, {70, 23}, {87, 40},
    {94, 62}, {94, 64}, {87, 86}, {70, 103},
    {48, 110}, {46, 110}, {24, 103}, {7, 86},
    {0, 64}, {0, 62}, {7, 40}, {24, 23}
};

point rtick[] =
{
    {46, 21}, {48, 21}, {67, 28}, {82, 43},
    {89, 62}, {89, 64}, {82, 83}, {67, 98},
    {48, 105}, {46, 105}, {27, 98}, {12, 83},
    {5, 64}, {5, 62}, {12, 43}, {27, 28}
};

point min_hand[] =
{
    {47, 24}, {51, 24}, {55, 25}, {59, 26}, {63, 28},
    {66, 30}, {69, 32}, {72, 34}, {75, 37}, {78, 40},
    {80, 44}, {82, 48}, {84, 52}, {85, 56}, {86, 60},
    {86, 63}, {86, 66}, {85, 70}, {84, 74}, {82, 78},
    {80, 82}, {78, 85}, {75, 88}, {72, 91}, {69, 94},
    {66, 96}, {62, 98}, {58, 99}, {55, 100}, {51, 101},
    {47, 101}, {43, 101}, {39, 100}, {36, 99}, {32, 98},
    {28, 96}, {25, 94}, {22, 91}, {19, 88}, {16, 85},
    {14, 82}, {12, 78}, {10, 74}, {9, 70}, {8, 66},
    {8, 63}, {8, 60}, {9, 56}, {10, 52}, {12, 48},
    {14, 44}, {16, 40}, {18, 37}, {21, 34}, {24, 32},
    {28, 30}, {31, 28}, {35, 26}, {39, 25}, {43, 24}
};

point hour_hand[] =
{
    {47, 35}, {51, 35}, {54, 36}, {58, 37},
    {61, 39}, {64, 41}, {67, 43}, {69, 46},
    {71, 49}, {73, 52}, {74, 56}, {75, 59},
    {75, 63}, {75, 66}, {74, 69}, {73, 73},
    {71, 77}, {69, 80}, {67, 83}, {64, 85},
    {61, 87}, {58, 89}, {54, 90}, {51, 91},
    {47, 91}, {44, 91}, {41, 90}, {37, 89},
    {33, 87}, {30, 85}, {27, 83}, {24, 81},
    {22, 78}, {20, 75}, {19, 71}, {18, 67},
    {18, 63}, {18, 59}, {19, 56}, {20, 52},
    {22, 49}, {24, 46}, {27, 43}, {30, 40},
    {33, 38}, {36, 37}, {40, 36}, {43, 35}
};

void swap(uint8_t *a, uint8_t *b)
{
    uint8_t temp = *a;
    *a = *b;
    *b = temp;
}

color24_t adjust_intensity(color24_t color, uint8_t intensity)
{
    color24_t temp = {color.red * intensity / 255,
                      color.green * intensity / 255,
                      color.blue * intensity / 255, 0};
    return temp;
}

void draw_wu_line(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, color24_t color)
{
    //Draw 2 endpoints
    pulse_set_draw_window(x0, y0, x0, y0);
    pulse_draw_point24(color);
    pulse_set_draw_window(x1, y1, x1, y1);
    pulse_draw_point24(color);

    //Negative slope
    bool negative = (y0 > y1) ? true : false;

    if(negative)
    {
        swap(&y0, &y1);
    }
    if(x0 > x1)
    {
        swap(&x0, &x1);
        negative ^= true;
    }
    uint8_t dx = x1 - x0;
    uint8_t dy = y1 - y0;

    if(!dx) //Vertical line
    {
        pulse_set_draw_window(x0, y0 + 1, x0, y1 - 1);
        for(int i = 1; i < dy; i++)
        {
            pulse_draw_point24(color);
        }
    }
    else if(!dy) //Horizontal line
    {
        pulse_set_draw_window(x0 + 1, y0, x1 - 1, y0);
        for(int i = 1; i < dx; i++)
        {
            pulse_draw_point24(color);
        }
    }
    else if(dx == dy) //45 degree line
    {
        unsigned char dy = (negative) ? -1 : 1;
        unsigned y = (negative) ? y1 : y0;
        for(int i = 1; i < dx; i++)
        {
            x0++;
            y += dy;
            pulse_set_draw_window(x0, y, x0, y);
            pulse_draw_point24(color);
        }
    }
    else //Other line
    {
        //Slope is > 1 or not
        bool steep  = (dy > dx) ? true : false;
        if(steep)
        {
            swap(&x0, &y0);
            swap(&x1, &y1);
            swap(&dx, &dy);
        }

        //Distance from ideal pixel center
        uint8_t D = 0;

        //Stores last pixel's distance
        uint8_t lastD = 0;

        //Distance increment
        uint8_t d = dy * 256 / dx;

        //Temp coordinates used to plot pixels
        uint8_t a0, a1, b0, b1;

        //Temp coordinate offset
        uint8_t da, db;

        while(x0 < x1)
        {
            x0++;;
            x1--;
            D += d;

            //Check for overflow
            if(lastD > D)
            {
                y0++;
                y1--;
            }
            lastD = D;
            a0 = x0;
            b0 = y0;
            a1 = x1;
            b1 = y1;
            da = 0;
            db = 1;
            if(negative & ~steep)
            {
                swap(&a0, &a1);
            }
            else if(negative & steep)
            {
                swap(&a0, &b0);
                swap(&a1, &b1);
                swap(&b0, &b1);
                swap(&da, &db);
            }
            else if(~negative & steep)
            {
                swap(&a0, &b0);
                swap(&a1, &b1);
                swap(&da, &db);
            }

            //Draw 4 points
            pulse_set_draw_window(a0, b0, a0, b0);
            pulse_draw_point24(adjust_intensity(color, ~D));
            pulse_set_draw_window(a0 + da, b0 + db, a0 + da, b0 + db);
            pulse_draw_point24(adjust_intensity(color, D));
            pulse_set_draw_window(a1, b1, a1, b1);
            pulse_draw_point24(adjust_intensity(color, ~D));
            pulse_set_draw_window(a1 - da, b1 - db, a1 - da, b1 - db);
            pulse_draw_point24(adjust_intensity(color, D));
        }
    }
}

void draw_hands()
{
    draw_wu_line(center.x, center.y, min_hand[current_min].x, min_hand[current_min].y, hand_color);
    draw_wu_line(center.x, center.y, hour_hand[4 * (current_hour % 12) + current_min / 15].x,
            hour_hand[4 * (current_hour % 12) + current_min / 15].y, hand_color);
}

void erase_hands()
{
    draw_wu_line(center.x, center.y, min_hand[current_min].x, min_hand[current_min].y, COLOR_BLACK24);
    draw_wu_line(center.x, center.y, hour_hand[4 * (current_hour % 12) + current_min / 15].x,
            hour_hand[4 * (current_hour % 12) + current_min / 15].y, COLOR_BLACK24);
}

void draw_time()
{
    pulse_cancel_timer(&sleep_timer);
    pulse_get_time_date(¤t_time);
    erase_hands();
    if(current_hour != current_time.tm_hour)
    {
        current_hour = current_time.tm_hour;
    }
    if(current_min != current_time.tm_min)
    {
        current_min = current_time.tm_min;
    }
    draw_hands();
    for(int i = 0; i < 16; i++)
    {
        draw_wu_line(Rtick[i].x, Rtick[i].y, rtick[i].x, rtick[i].y, tick_color);
    }
    sleep_timer = pulse_register_timer(SLEEP_TIMEOUT, &pulse_update_power_down_timer, 0);
}

void draw_spinning_time()
{
    erase_hands();
    pulse_get_time_date(¤t_time);
    uint8_t temp_min = current_time.tm_min;
    uint8_t temp_hour = current_time.tm_hour % 12;
    current_min = 0;
    current_hour = 0;
    while(temp_min != current_min || temp_hour != current_hour)
    {
        draw_hands();
        erase_hands();
        current_min++;
        if(current_min == 60)
        {
            current_min = 0;
            current_hour++;
        }
    }
    draw_hands();
}

void main_app_init()
{
    current_min = 0;
    current_hour = 0;
    draw_time();
    pulse_register_callback(ACTION_WOKE_FROM_BUTTON, &draw_time);
}

void main_app_handle_button_down()
{
    pulse_cancel_timer(&sleep_timer);
    draw_spinning_time();
    sleep_timer = pulse_register_timer(SLEEP_TIMEOUT, &pulse_update_power_down_timer, 0);
}

void main_app_handle_button_up()
{
   
}

void main_app_loop()
{

}

void main_app_handle_doz()
{

}

void main_app_handle_hardware_update(enum PulseHardwareEvent event)
{

}


Offline
 Profile  
 
 Post subject: Re: Analog Clock
PostPosted: Tue Mar 08, 2011 1:11 am 
User avatar

Joined: Mon Feb 14, 2011 7:07 pm
Posts: 172
Embedded video...go!



_________________
---

Lead designer of inPulse
Offline
 Profile  
 
 Post subject: Re: Analog Clock
PostPosted: Tue Mar 08, 2011 12:28 pm 

Joined: Thu Feb 17, 2011 1:42 pm
Posts: 13
Location: Canada
this needs to be on the BB app, now! lol loving it!! thats exactly what i want for the BB notification app!! :)



_________________
Original InPulse Watch beta tester!

Check out my BlackBerry themes!
Click here to take a look!
Offline
 Profile  
 
 Post subject: Re: Analog Clock
PostPosted: Tue Mar 08, 2011 4:18 pm 

Joined: Sun Feb 27, 2011 8:32 pm
Posts: 139
Location: Where ever the USAF sends me.
I've got the original analog clock merged with the notification app, this one would actually probably work better. I'll see what i can do to merge this one with it. Big problem is keeping the overall file size below the max allowed when merging these two programs.



_________________
Page ID: KTS
Offline
 Profile  
 
 Post subject: Re: Analog Clock
PostPosted: Tue Mar 08, 2011 4:31 pm 

Joined: Thu Feb 17, 2011 1:42 pm
Posts: 13
Location: Canada
ya what i want... is the BB notification app and an analogue clock face... so if you can make that happen then me a happy guy, along with alot of other BB guys



_________________
Original InPulse Watch beta tester!

Check out my BlackBerry themes!
Click here to take a look!
Offline
 Profile  
 
 Post subject: Re: Analog Clock
PostPosted: Tue Mar 08, 2011 5:02 pm 

Joined: Tue Feb 15, 2011 10:35 pm
Posts: 42
c_86 wrote:
ya what i want... is the BB notification app and an analogue clock face... so if you can make that happen then me a happy guy, along with alot of other BB guys

Glad to see people are liking the app. We'll definitely consider putting the analog clock in the BB app. We also plan to add the draw line function to the SDK.

Killer Turtle wrote:
I've got the original analog clock merged with the notification app, this one would actually probably work better. I'll see what i can do to merge this one with it. Big problem is keeping the overall file size below the max allowed when merging these two programs.

That would be cool. The code isn't as optimized as it could be so if you need to reduce code space you can simplify the lookup tables for the hands and ticks by only storing points in the first octant and mirroring them as needed for drawing.


Offline
 Profile  
 
 Post subject: Re: Analog Clock
PostPosted: Tue Mar 08, 2011 5:57 pm 

Joined: Sun Feb 27, 2011 8:32 pm
Posts: 139
Location: Where ever the USAF sends me.
Yeah I've been trimming it down. I have one version that i am working on that removed all the bluetooth icon code, but it's still too large, so I'll try your suggestion and see what else I can do.



_________________
Page ID: KTS
Offline
 Profile  
 
 Post subject: Re: Analog Clock
PostPosted: Wed Mar 09, 2011 3:36 pm 

Joined: Sun Feb 27, 2011 8:32 pm
Posts: 139
Location: Where ever the USAF sends me.
What is the max size the comiled code can be? I'm asking this because when I build my Analog Notification app, i get a build file size of 46Kb. when I build just the Notification app I get a file size of 45Kb. I thought it couldn't be larger then 32Kb.

I guess I really need to wait for my watch to get here to test my analog app to see if it will load to it or not.



_________________
Page ID: KTS
Offline
 Profile  
 
 Post subject: Re: Analog Clock
PostPosted: Wed Mar 09, 2011 7:47 pm 

Joined: Sun Feb 27, 2011 11:32 am
Posts: 71
Ryan wrote:
.... if you need to reduce code space you can simplify the lookup tables for the hands and ticks by only storing points in the first octant and mirroring them as needed for drawing.

Depending on how large your table is right now, you might find my fixed point sin_lookup() function useful. It compiles to about 130 bytes and is accurate to 0.0075 once the results are scaled. Essentially it is the same thing Ryan is suggesting: the table only stores 16 points in the first quadrant, then interpolates between those points to provide higher accuracy. If you're doing minutes, you could get by with just 15 points and eliminate the interpolation. Remember that cos(x) == sin(x+90), so you do not need both sin and cos (or x and y) tables.


Offline
 Profile  
 
 Post subject: Re: Analog Clock
PostPosted: Wed Mar 09, 2011 11:03 pm 

Joined: Tue Feb 15, 2011 10:35 pm
Posts: 42
Killer Turtle wrote:
What is the max size the comiled code can be? I'm asking this because when I build my Analog Notification app, i get a build file size of 46Kb. when I build just the Notification app I get a file size of 45Kb. I thought it couldn't be larger then 32Kb.

After an app is compiled you get a .bin file and a .hex file. The .bin file is what gets sent to the watch and should be 32Kb which is the max size. We use the .hex file internally and its size will vary depending on the code.

A sine table would be another good way to reduce the code size as hudson mentioned in the previous post.


Offline
 Profile  
 
 Post subject: Re: Analog Clock
PostPosted: Tue Mar 15, 2011 9:52 pm 

Joined: Tue Mar 15, 2011 9:24 pm
Posts: 3
Ryan's simple clock fits into the notifications app and has 500 bytes to spare.
I did not include the code for animating the time.

Openwatch finally connects and stops saying "Watch Disconnected".
Time is correct. Have not seen any notifications work yet.
Using Android 2.1 on My Touch Slide (T-Mobile).

Just started playing with this little jewel.
I will know more soon.

Film at 11...


Attachments:
File comment: Looks like this...

DSCN0309b.jpg [ 131.54 KiB | Viewed 581 times ]
Offline
 Profile  
 
 Post subject: Re: Analog Clock
PostPosted: Tue Mar 15, 2011 10:47 pm 
User avatar

Joined: Mon Feb 14, 2011 7:07 pm
Posts: 172
Looks awesome! You can send a test message with Openwatch to test it out. Let us know how it goes!



_________________
---

Lead designer of inPulse
Offline
 Profile  
 
 Post subject: Re: Analog Clock
PostPosted: Wed Mar 16, 2011 10:52 pm 

Joined: Mon Feb 21, 2011 1:20 am
Posts: 7
mmelmers wrote:
Ryan's simple clock fits into the notifications app and has 500 bytes to spare.
I did not include the code for animating the time.

Openwatch finally connects and stops saying "Watch Disconnected".
Time is correct. Have not seen any notifications work yet.
Using Android 2.1 on My Touch Slide (T-Mobile).

Just started playing with this little jewel.
I will know more soon.

Film at 11...


Can you Upload the version you have of the notification app with the clock?



_________________
ORIGINAL BETA TESTER
Offline
 Profile  
 
 Post subject: Re: Analog Clock
PostPosted: Fri Mar 18, 2011 10:57 am 

Joined: Tue Mar 15, 2011 9:24 pm
Posts: 3
Yes, I sent a Notification from Windows (see pic).
Notice the "Not Connected" icon is off.

Still have not got Notification from OpenWatch to my annoyatron.
The original notifications app does not work either, so I don't think I broke anything.
Probably just phone config.

I bt to headsets for phone and audio all the time so I know the phone works.
I will try my own simple apps from the phone next, so I can tell what's not happy.

Such a cool little product :-)

Martin


Attachments:

DSCN0312b.jpg [ 115.99 KiB | Viewed 486 times ]
Offline
 Profile  
 
 Post subject: Re: Analog Clock
PostPosted: Fri Mar 25, 2011 9:08 am 

Joined: Tue Mar 15, 2011 9:24 pm
Posts: 3
Sorry, I meant from Openwatch ON my Annoyatron.


Offline
 Profile  
 
 Post subject: Re: Analog Clock
PostPosted: Sat Mar 26, 2011 12:30 am 

Joined: Fri Mar 18, 2011 10:56 pm
Posts: 9
This is so slick!!! Love it.


Offline
 Profile  
 
 Post subject: Re: Analog Clock
PostPosted: Sat Mar 26, 2011 7:21 am 

Joined: Thu Feb 17, 2011 1:42 pm
Posts: 13
Location: Canada
i want this on my BB app and watch.... argh....



_________________
Original InPulse Watch beta tester!

Check out my BlackBerry themes!
Click here to take a look!
Offline
 Profile  
 
 Post subject: Re: Analog Clock
PostPosted: Sun Mar 27, 2011 11:22 am 
User avatar

Joined: Mon Feb 14, 2011 7:07 pm
Posts: 172
@mmelmers would you mind posting the source so other people could load this on their watches? Only if you don't mind...



_________________
---

Lead designer of inPulse
Offline
 Profile  
 
 Post subject: Re: Analog Clock
PostPosted: Sat Apr 09, 2011 2:57 pm 

Joined: Wed Apr 06, 2011 8:53 pm
Posts: 32
Thank you Ryan for sharing the code! :) I was able to make it run on the simulator (but pressing the button does nothing, for some reason).


Offline
 Profile  
 
Display posts from previous:  Sort by  
 Page 1 of 1 [ 19 posts ] 

All times are UTC - 8 hours


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: