[HD2 Android NAND Development] kokotas:
This is an experiment - project. It is about adding off-mode alarm clock to the HD2.

(If you don't have cLK installed (at least v1.5.1.4), then this is not applicable for you)

After ~10 months, zicoxx asked more or less the same thing:

So lets see what we have so far...

This project depends on 3 factors, (1)Kernel, (2)Android application, (3)Bootloader.

Kernel

The kernel has a function in arch\arm\mach-msm\pm.c which handles the reboot reason:

static int msm_reboot_call(struct notifier_block *this, unsigned long code, void *_cmd)
{
if((code == SYS_RESTART) && _cmd) {
char *cmd = _cmd;
if (!strcmp(cmd, "bootloader")) {
restart_reason = 0x77665500;
} else if (!strcmp(cmd, "recovery")) {
restart_reason = 0x77665502;
} else if (!strcmp(cmd, "eraseflash")) {
restart_reason = 0x776655EF;
} else if (!strncmp(cmd, "oem-", 4)) {
unsigned code = simple_strtoul(cmd + 4, 0, 16) & 0xff;
restart_reason = 0x6f656d00 | code;
[COLOR="YellowGreen"]
//This is the proposed patch to our kernel
//(thanks Rick_1995 for suggesting it to bypass the time limit of 255 min)
} else if (!strncmp(cmd, "S", 1)) {
unsigned code = simple_strtoul(cmd + 1, 0, 16) & 0x00ffffff;
restart_reason = 0x53000000 | code;
[/COLOR]
} else if (!strcmp(cmd, "force-hard")) {
restart_reason = 0x776655AA;
} else {
restart_reason = 0x77665501;
}
}
return NOTIFY_DONE;
}

Not being able to compile a new kernel with a change like the green text in the above function, I just used the "oem-" prefix in the reboot reason passed from the application. The downside of this is that we can't set an alarm for more than 255 min from the current time.

Application

The application is able to:

reboot the device using the PowerManager class since it is signed and placed in /system/app:

//MinutesToSuspend is set using a TimePicker
mPowerManager.reboot("oem-" + MinutesToSuspend);
[COLOR="YellowGreen"]
//In case we have a kernel with the above patch included
mPowerManager.reboot("S" + MinutesToSuspend);[/COLOR]

play the alarm when the device has booted usind the BroadcastReceiver class that will get the BOOT_COMPLETED action.

Bootloader

The bootloader (in this case cLK):

detects the boot reason and decodes the MinutesToSuspend from it and enters a sort of suspend mode with a timeout equal to MinutesToSuspend converted to msec

if(target_check_reboot_mode() == (target_check_reboot_mode() | 0x6f656d00)) {
char str[16];
char *endptr;
unsigned MinutesToSuspend;
unsigned msecToSuspend = 0;
// Decode the MinutesToSuspend from the reboot_mode
sprintf(str, "%i", (target_check_reboot_mode() ^ 0x6f656d00));
MinutesToSuspend = strtol(str, &endptr, 16);
if (MinutesToSuspend < 3)
msecToSuspend = (MinutesToSuspend * 60000);
else
msecToSuspend = (MinutesToSuspend * 60000) - (120000);

suspend_time = msecToSuspend;
show_multi_boot_screen = 0;
boot_into_recovery = 0;
}
[COLOR="YellowGreen"]
//In case we have a kernel with the above patch included
#define MARK_ALARM_TAG	0x53000000
if(target_check_reboot_mode() & 0xFF000000 == MARK_ALARM_TAG) {
uint32_t MinutesToSuspend;
// Decode the MinutesToSuspend from the reboot_mode
MinutesToSuspend = target_check_reboot_mode() ^ MARK_ALARM_TAG;
if (MinutesToSuspend > 3)
MinutesToSuspend -= 2;

suspend_time = MinutesToSuspend * 60000;
show_multi_boot_screen = 0;
boot_into_recovery = 0;
}
[/COLOR]
if(suspend_time) {
msm_acpu_clock_init(1); // 384MHz (acpu_freq_tbl[0])
//Could try setting cpu clock at 245...
//msm_acpu_clock_init(0); // 245MHz (acpu_freq_tbl[0])
htcleo_suspend(suspend_time);
}

the suspend mode is implemented using this function

#define DS2746_SAFE_CHG_VOLTAGE	4200 // mV

void htcleo_suspend(unsigned timeout)
{
uint32_t	voltage;
//int16_t	current;
bool	usb_cable_connected;
time_t	start_time;

start_time = current_time();
if (timeout)
htcleo_panel_bkl_pwr(0);

do {
//current = ds2746_current(DS2746_I2C_SLAVE_ADDR, 1200);
voltage = ds2746_voltage(DS2746_I2C_SLAVE_ADDR);
usb_cable_connected = htcleo_usb_online();

if (usb_cable_connected) {
if (voltage < DS2746_SAFE_CHG_VOLTAGE) {
// If battery needs charging, set new charger state
if (htcleo_ac_online()) {
if (htcleo_charger_state() != CHG_AC ) {
writel(0x00080000, USB_USBCMD);
ulpi_write(0x48, 0x04);
htcleo_set_charger(CHG_AC);
}
} else {
if (htcleo_charger_state() != CHG_USB_LOW ) {
writel(0x00080001, USB_USBCMD);
mdelay(10);
htcleo_set_charger(CHG_USB_LOW);
}
}
// Led = solid amber
if (htcleo_notif_led_mode != 2)
thread_resume(thread_create("htcleo_notif_led_set_mode_2",
&htcleo_notif_led_set_mode,
(void *)2,
HIGH_PRIORITY,
DEFAULT_STACK_SIZE));
} else {
// Battery is full
if(timeout) {
// Set charger state to CHG_OFF_FULL_BAT
if (htcleo_charger_state() != CHG_OFF_FULL_BAT ) {
writel(0x00080001, USB_USBCMD);
mdelay(10);
htcleo_set_charger(CHG_OFF_FULL_BAT);
}
// and turn led solid green
if (htcleo_usb_online() && (htcleo_notif_led_mode != 1))
thread_resume(thread_create("htcleo_notif_led_set_mode_1",
&htcleo_notif_led_set_mode,
(void *)1,
HIGH_PRIORITY,
DEFAULT_STACK_SIZE));
} else {
// exit while if we don't have a timeout
break;
}
}
} else {
// Set charger state to CHG_OFF
if (htcleo_charger_state() != CHG_OFF ) {
writel(0x00080001, USB_USBCMD);
mdelay(10);
htcleo_set_charger(CHG_OFF);
}
// and turn off led
if (htcleo_notif_led_mode != 0)
thread_resume(thread_create("htcleo_notif_led_set_off",
&htcleo_notif_led_set_mode,
(void *)0,
HIGH_PRIORITY,
DEFAULT_STACK_SIZE));
}
// While in loop keep tracking if POWER button is pressed
// in order to (re)boot the device
for (int i=0; i<6; i++) {
if(keys_get_state(KEY_POWER)!=0) {
target_reboot(0);
return;//:)
}
mdelay(96);//total delay ~500ms per loop
}
// And check if timeout exceeded in order to reboot
if (timeout && (current_time() - start_time >= timeout))
target_reboot(0);
} while ( (usb_cable_connected) /* && current >= 0) */
||(timeout) ); // If we have a timeout this while-loop never breaks if we don't reboot.

// Double check voltage
mdelay(10);
voltage = ds2746_voltage(DS2746_I2C_SLAVE_ADDR);

if (voltage < DS2746_SAFE_CHG_VOLTAGE) {
// If battery is not full then
// EITHER the cable is unplugged
// OR the double check of voltage gave us
// a value less than the safe voltage.
// Set charger state to CHG_OFF
writel(0x00080001, USB_USBCMD);
mdelay(10);
htcleo_set_charger(CHG_OFF);
} else {
// If battery is full
// set charger state to CHG_OFF_FULL_BAT
writel(0x00080001, USB_USBCMD);
mdelay(10);
htcleo_set_charger(CHG_OFF_FULL_BAT);
// and turn led solid green
if (htcleo_usb_online() && (htcleo_notif_led_mode != 1))
thread_resume(thread_create("htcleo_notif_led_set_mode_1",
&htcleo_notif_led_set_mode,
(void *)1,
HIGH_PRIORITY,
DEFAULT_STACK_SIZE));
// While usb cable is connected
// keep tracking if POWER button is pressed OR timeout exceeded
// in order to (re)boot the device
while (htcleo_usb_online()) {
if(keys_get_state(KEY_POWER)!=0)
target_reboot(0);
/* if (timeout && (current_time() - start_time >= timeout))
break; */
}
}

// If we've set a timeout and reached it, reboot the device
/* if (timeout && (current_time() - start_time >= timeout))
target_reboot(0); */

// Shutdown the device
enter_critical_section();
platform_exit();
msm_proc_comm(PCOM_POWER_DOWN, 0, 0);
for (;;) ;
}

Any suggestions or observations are welcomed!

This is open for everyone to use or contribute. Source is available at https://github.com/n0d3/HD2_Alarm_Clock

If you have to ask for an apk to test, then you may download this example's apk from here.But don't consider this as an application release thread.