Porting Guide/System

From Tizen Wiki
Jump to: navigation, search

systemd

As a system and service manager for Tizen system, systemd (ver. 43), is newly applied to platform. It is a replacement for the System V init daemon. Basically, systemd provides a lot of functionality such as parallelized service execution, socket and D-Bus activation for starting services and daemon, on-demand starting of deamons, managing the service processes as a group using Linux cgroup, supporting automount points, snapshotting, and restoring of services.

The following figure shows the systemd architecture.

Systemd arch.PNG

systemd Utility

systemd provides developers with a lot of utilities for monitoring and controlling the systemd itself and its services. For example, you can query or send control commands to the systemd service manager using the systemctl utility. To see the log message, you can query the systemd journal using the systemd-journalctl utility.

systemd Target

Tizen boot-up process is split up in various discrete steps. Each step is grouped to its unit using a target unit to synchronize the point. The boot-up process is highly parallelized in each target, which means that the order in which the specific target units are reached is not deterministic.

systemd Daemon

The systemd daemon is a system and service manager for Tizen platform. When it runs as a first process on boot, it acts as an initialization system that brings up the system. If the systemd daemon is launched with the --user option, it runs as a user session. The systemd-journald is a system service that collects and stores log data from the kernel and from user processes using syslog or STDOUT/STDERR.

systemd Core

The systemd core part manages all units, such as service, socket, and mount, and stores all log data. The systemd core is controlled by using a systemd utility, such as systemctl.

systemd Library & Linux Kernel

systemd requires that the cgroup and autofs options are enabled in the Linux Kernel configuration. It also depends on dbus and some libraries, such as libnotify and libudev.

System Framework

The System framework module abstracts low level system functions and manages the Tizen platform, in terms of platform policy, with the following major functionalities.

Systemframework.png

The following subsections introduce the System framework sub-components.

System Server

The system server handles system events, such as memory status, battery level, and plug and play device status, as well as process watchdog.

Power Manager

The power manager is a session daemon that runs to manage the power for a system. It provides conditional state transition. The power manager transitions with any wake-up event, shifting to a higher power state. Similarly, based on timeouts, it transits to the next lower power state. The Tizen Power manager functionalities control the display backlight dimming/off and device sleep.

Power Manager Conditional State Transition

When an application, such as a media player, is running, there may be no input from the user for a long time, but the display must not be dimmed or switched off. The applications can request that the Power manager does not change the display to a specific state.

Conditional State Transition

Lock: Keep the system from entering lower state than the specific state. For example, lock(LCD_OFF) forces system to be in the LCD_NORMAL, LCD_DIM, or LCD_OFF state.

Unlock: Allow system to enter lower state than specific state

You have the following options to control the device’s power status and sleep mode.

sys interface: /sys/power/state					
               /sys/power/wakeup_count
               /dev/event0					
               /dev/event1

Device Manager

The device manager provides the following features:

  • Providing the interface to controlling all devices
  • LCD backlight dimming/off, application processor sleep
  • System monitoring and event handling from devices and system
  • Process, battery level, and low memory monitoring
  • USB, MMC, charger, and ear jack event handling
  • Interfaces for accessing devices
  • LCD, touch, LED, vibrator

USB manager

With the USB manager, you can:

  • Set USB configurations to connect to the PC
  • Monitor external USB host devices, such as keyboards, mice, cameras, USB storages, and USB printers
  • Monitor USB accessories which are compatible with the Android USB accessories

System OAL

The System OAL interface provides function pointers for OEMs to plug in their device or platform specific code to the System framework.

Porting OAL Interface

The OAL interface provides function pointers for OEMs to plugin their device/platform specific code to System framework.

OEM developers must implement the API defined in the devman_plugin_intf.h header file and compile their library as a libslp_devman_plugin.so file. OEM APIs can be grouped as power, battery, haptics, LED, light, and memory. On initialization, the Device Manager (devman) calls the OEM_sys_get_devman_plugin_interface() function, which in turn returns the address of implemented OEM APIs. When applications request the device manager APIs, the appropriate OEM APIs referred by the OEM_sys_devman_plugin_interface() function are be called.

The devman library uses sysfs for interfaces with device drivers and kernel. sysfs is a virtual file system provided by Linux 2.6 or above.

Configuration

Install the OEM library as libslp_devman_plugin.so to the /usr/lib directory.

The OAL API definitions are in the devman_plugin_intf.h header file:

typedef struct {
    int (*OEM_sys_get_display_count) (int *value);

    int (*OEM_sys_get_backlight_min_brightness) (int index, int *value);
    int (*OEM_sys_get_backlight_max_brightness) (int index, int *value);
    int (*OEM_sys_get_backlight_brightness) (int index, int *value, int power_saving);
    int (*OEM_sys_set_backlight_brightness) (int index, int value, int power_saving);

    int (*OEM_sys_set_backlight_dimming) (int index, int value);

    int (*OEM_sys_get_backlight_acl_control) (int index, int *value);
    int (*OEM_sys_set_backlight_acl_control) (int index, int value);

    int (*OEM_sys_get_lcd_power) (int index, int *value);
    int	(*OEM_sys_set_lcd_power) (int index, int value);

    int	(*OEM_sys_get_image_enhance_mode) (int *value);
    int	(*OEM_sys_set_image_enhance_mode) (int value);
    int	(*OEM_sys_get_image_enhance_scenario) (int *value);
    int	(*OEM_sys_set_image_enhance_scenario) (int value);
    int	(*OEM_sys_get_image_enhance_tone) (int *value);
    int	(*OEM_sys_set_image_enhance_tone) (int value);
    int	(*OEM_sys_get_image_enhance_outdoor) (int *value);
    int	(*OEM_sys_set_image_enhance_outdoor) (int value);

    int	(*OEM_sys_get_image_enhance_tune) (int *value);
    int	(*OEM_sys_set_image_enhance_tune) (int value);

    int	(*OEM_sys_image_enhance_info) (int *value);

    int	(*OEM_sys_set_display_frame_rate) (int value);

    int	(*OEM_sys_get_uart_path) (int *value);
    int	(*OEM_sys_set_uart_path) (int value);

    int	(*OEM_sys_get_usb_path) (int *value);
    int	(*OEM_sys_set_usb_path) (int value);

    int	(*OEM_sys_get_haptic_vibetones_level_max) (int *value);
    int	(*OEM_sys_get_haptic_vibetones_level) (int *value);
    int	(*OEM_sys_set_haptic_vibetones_level) (int value);
    int	(*OEM_sys_set_haptic_vibetones_enable) (int value);
    int	(*OEM_sys_set_haptic_vibetones_oneshot) (int value);

    int	(*OEM_sys_get_battery_capacity) (int *value);
    int	(*OEM_sys_get_battery_capacity_raw) (int *value);
    int	(*OEM_sys_get_battery_charge_full) (int *value);
    int	(*OEM_sys_get_battery_charge_now) (int *value);
    int	(*OEM_sys_get_battery_present) (int *value);
    int	(*OEM_sys_get_battery_health) (int *value);
    int	(*OEM_sys_get_battery_polling_required) (int *value);

    int	(*OEM_sys_get_jack_charger_online) (int *value);
    int	(*OEM_sys_get_jack_earjack_online) (int *value);
    int	(*OEM_sys_get_jack_earkey_online) (int *value);
    int	(*OEM_sys_get_jack_hdmi_online) (int *value);
    int	(*OEM_sys_get_jack_usb_online) (int *value);
    int	(*OEM_sys_get_jack_cradle_online) (int *value);
    int	(*OEM_sys_get_jack_tvout_online) (int *value);
    int	(*OEM_sys_get_jack_keyboard_online) (int *value);

    int	(*OEM_sys_get_leds_torch_max_brightness) (int *value);
    int	(*OEM_sys_get_leds_torch_brightness) (int *value);
    int	(*OEM_sys_set_leds_torch_brightness) (int value);

    /* TODO: Change args type */
    int	(*OEM_sys_set_power_state) (int value);

    /* TODO: Determine enum values of wakeup_count nodes */
    int	(*OEM_sys_get_power_wakeup_count) (int *value);
    int	(*OEM_sys_set_power_wakeup_count) (int value);

    int	(*OEM_sys_get_memnotify_node) (char *node);
    int	(*OEM_sys_get_memnotify_victim_task) (int *value);
    int	(*OEM_sys_set_memnotify_threshold_lv1) (int value);
    int	(*OEM_sys_set_memnotify_threshold_lv2) (int value);

    int	(*OEM_sys_get_process_monitor_node) (char *node);
    int	(*OEM_sys_set_process_monitor_mp_pnp) (int value);
    int	(*OEM_sys_set_process_monitor_mp_vip) (int value);

    int	(*OEM_sys_get_cpufreq_cpuinfo_max_freq) (int *value);
    int	(*OEM_sys_get_cpufreq_cpuinfo_min_freq) (int *value);
    int	(*OEM_sys_get_cpufreq_scaling_max_freq) (int *value);
    int	(*OEM_sys_set_cpufreq_scaling_max_freq) (int value);
    int	(*OEM_sys_get_cpufreq_scaling_min_freq) (int *value);
    int	(*OEM_sys_set_cpufreq_scaling_min_freq) (int value);
} 
OEM_sys_devman_plugin_interface; 
const OEM_sys_devman_plugin_interface *OEM_sys_get_devman_plugin_interface();

The Device manager (devman) gets the pointer to the OEM_sys_get_devman_plugin_interface structure in the plugin_intf variable, as shown in the following code snippet.

const
OEM_sys_devman_plugin_interface *(*OEM_sys_get_devman_plugin_interface) ();
    
OEM_sys_get_devman_plugin_interface = dlsym(dlopen_handle, "OEM_sys_get_devman_plugin_interface");
if ((error = dlerror()) != NULL) {
    ERR("dlsym() failed: %s", error);
    dlclose(dlopen_handle);

    return;
}

plugin_intf = OEM_sys_get_devman_plugin_interface();

if (!plugin_intf) {
    ERR("get_devman_plugin_interface() failed");
    dlclose(dlopen_handle);

    return;
}

The following example shows the implementation code for the OEM_sys_get_backlight_brightness() function. This function gets the current brightness of the backlight unit and the output is stored in the value variable. The value can range from 0 <= value <= MAX_BACKLIGHT_BRIGHTNESS.

The path for the input and output parameters of the OEM APIs can be found in the devman_define_node_path.h header file.

#define BATTERY_CAPACITY_PATH "/sys/class/power_supply/battery/capacity"
#define BATTERY_CHARGE_FULL_PATH "/sys/class/power_supply/battery/charge_full"
#define BACKLIGHT_PATH "/sys/class/backlight/"
#define BACKLIGHT_MAX_BRIGHTNESS_PATH BACKLIGHT_PATH"%s/max_brightness"
#define BACKLIGHT_BRIGHTNESS_PATH BACKLIGHT_PATH"%s/brightness"

int
OEM_sys_get_backlight_brightness(int index, int *value, int power_saving)
{
    int ret = -1;
    char path[MAX_NAME+1];
    int max_brightness;
    int pwr_saving_offset;

    if (index >= DISP_MAX) {
        devmgr_log("supports %d display node", DISP_MAX);

        return ret;
    }

    snprintf(path, MAX_NAME, BACKLIGHT_BRIGHTNESS_PATH, disp_info[index].bl_name);
    ret = sys_get_int(path, value);
    devmgr_log("path[%s]value[%d]power_saving[%d]", path, *value, power_saving);

    if (power_saving) {
        snprintf(path, MAX_NAME, BACKLIGHT_MAX_BRIGHTNESS_PATH, disp_info[index].bl_name);
        ret = sys_get_int(path, &max_brightness);
        if (ret) {
            devmgr_log("Can't read max_brightness node[%s]", path);

            return ret;
        }
	pwr_saving_offset = (PWR_SAVING_CANDELA_CRITERION * max_brightness / MAX_CANDELA_CRITERION) + 0.5;

	if (*value > max_brightness - pwr_saving_offset)
	    *value = max_brightness;
	else
	    *value = *value + pwr_saving_offset;

	devmgr_log("power_saving result[%d]", *value);
    }

    return ret;
}

The sys_get_int() function provides access to the kernel device driver node parameters. The path parameter is defined in the devman_define_node_path.h header file, as described above. The value to get or set is stored in the value parameter. In similar ways , functions, such as sys_get_str(), sys_set_int(), sys_set_str(), and sys_get_node() are implemented to set or get the parameter values at the respective path. The following example shows the implementation for the sys_get_int().

int
sys_get_int(char *fname, int *val)
{
    char buf[BUFF_MAX];

    if (sys_read_buf(fname, buf) == 0) {
	*val = atoi(buf);
	
        return 0;
    } else {
	*val = -1;

	return -1;
    }
}
static int
sys_read_buf(char *file, char *buf)
{
    int fd;
    int r;

    fd = open(file, O_RDONLY);
    if (fd == -1) {
	return -ENOENT;
    }

    r = read(fd, buf, BUFF_MAX);
    if ((r >= 0) && (r < BUFF_MAX))
	buf[r] = '\0';
    else {
	return -EIO;
    }

    close(fd);

    return 0;
}

Power Manager

The various power states include Normal, LCD_DIM, LCD_OFF, and SLEEP and the device can switch from one state to another, as shown in the above diagram. The power states are defined in the following enumeration.

typedef enum {
    POWER_STATE_NORMAL, /* Normal state */
    POWER_STATE_SCREEN_DIM, /* Screen dim state */
    POWER_STATE-SCREEN_OFF, /* Screen off state */
} power_state_e;
Function Prototype Description (0-success, others -failure)
int (*OEM_sys_set_power_state) (int value); The function sets the device to suspend mode (0: Suspend Mode). Mandatory
int (*OEM_sys_get_power_wakeup_count) (int *value); The function gets the current wakeup_count. Mandatory
int (*OEM_sys_set_power_wakeup_count) (int value); The function sets the wakeup_count with input value. Mandatory
int (*OEM_sys_get_cpufreq_cpuinfo_max_freq) (int *value); The function gets the limitation of the maximum CPU frequency value in KHz. Optional
int (*OEM_sys_get_cpufreq_cpuinfo_min_freq) (int *value); The function gets the limitation of the minimum CPU frequency value in KHz. Optional
int (*OEM_sys_get_cpufreq_scaling_max_freq) (int *value); The function gets the current maximum CPU frequency in KHz.

(CPUINFO_MIN_FREQ <= value <= CPUINFO_MAX_FREQ)

Optional
int (*OEM_sys_set_cpufreq_scaling_max_freq) (int value); The function sets the current maximum CPU frequency in KHz.

(CPUINFO_MIN_FREQ <= value <= CPUINFO_MAX_FREQ)

Optional
int (*OEM_sys_get_cpufreq_scaling_min_freq) (int *value); The function gets the current minimum CPU frequency in KHz.

(CPUINFO_MIN_FREQ <= value <= CPUINFO_MAX_FREQ)

Optional
int (*OEM_sys_set_cpufreq_scaling_min_freq) (int value); The function sets the current minimum CPU frequency in KHz.

(CPUINFO_MIN_FREQ <= value <= CPUINFO_MAX_FREQ)

Optional
int (*OEM_sys_get_uart_path) (int *value); The function gets the current path of the uart node.

(0: CP, 1: AP)

Optional
int (*OEM_sys_set_uart_path) (int value); The function sets the current path of the uart node.

(0: CP, 1: AP)

Optional
int (*OEM_sys_get_usb_path) (int *value); The function gets the current path of the USB node.

(0: CP, 1: AP)

Optional
int (*OEM_sys_set_usb_path) (int value); The function sets the current path of the USB node.

(0: CP, 1: AP)

Optional
int (*OEM_sys_get_jack_charger_online) (int *value); The function gets the charger online status.

(0: Offline, 1: Online)

Mandatory
int (*OEM_sys_get_jack_earjack_online) (int *value); The function gets the earjack online status.

(0: Offline, 1: Online)

Mandatory
int (*OEM_sys_get_jack_earkey_online) (int *value); The function gets the earkey online status.

(0: Offline, 1: Online)

Mandatory
int (*OEM_sys_get_jack_hdmi_online) (int *value); The function gets the HDMI online status.

(0: Offline, 1: Online)

Optional
int (*OEM_sys_get_jack_usb_online) (int *value); The function gets the USB online status.

(0: Offline, 1: Online)

Optional
int (*OEM_sys_get_jack_cradle_online) (int *value); The function gets the cradle online status

.(0: Offline, 1: Online)

Optional
int (*OEM_sys_get_jack_tvout_online) (int *value); The function gets the TV out online status.

(0: Offline, 1: Online)

Optional
int(*OEM_sys_get_jack_keyboard_online) (int *value); The fuction gets the keyboard interface status. Optional

Vibrator

Vibrator interfaces are used to for accessing the vibrator device. They provides functions to control and retrieve vibrator parameters.

Function Prototype Description (0: Success, Others: Failed)
int (*OEM_sys_get_haptic_vibetones_level_max) (int *value) The function gets the maximum vibration feedback intensity level. Optional
int (*OEM_sys_get_haptic_vibetones_level) (int *value) The function gets the current vibration feedback intensity level.

(0 <= value <= VIBETONES_LEVEL_MAX)

Optional
int (*OEM_sys_set_haptic_vibetones_level) (int value) The function sets the current vibration feedback intensity level.

(0 <= value <= VIBETONES_LEVEL_MAX)

Optional
int (*OEM_sys_set_haptic_vibetones_enable) (int value) The function enables the vibration with current intensity level.

(0: Off, 1: On)

Mandatory
int (*OEM_sys_set_haptic_vibetones_oneshot) (int value) The function enables the oneshot vibration with current intensity level (milliseconds). Optional

Image Enhancement

Image Enhancement interfaces provides functions to control the Image Quality Enhancement Algorithm.

Function Prototype Description (0: Success, Others: Failed)
int (*OEM_sys_get_image_enhance_mode) (int *value); The function gets the image enhance algorithm mode.

(0: DYNAMIC, 1: STANDARD, 2: NATURAL, 3: MOVIE)

Optional
int (*OEM_sys_set_image_enhance_mode) (int value); The function sets the image enhance algorithm mode.

(0: DYNAMIC, 1 : STANDARD, 2 : NATURAL, 3 : MOVIE)

Optional
int (*OEM_sys_get_image_enhance_scenario) (int *value); The function gets the image enhance algorithm scenario.

(0: UI, 1: GALLERY, 2: VIDEO, 3: VTCALL, 4: CAMERA, 5: BROWSER, 6: NEGATIVE, 7: BYPASS)

Optional
int (*OEM_sys_set_image_enhance_scenario) (int value); The function sets the image enhance algorithm scenario.

(0: UI, 1: GALLERY, 2: VIDEO, 3: VTCALL, 4: CAMERA, 5: BROWSER, 6: NEGATIVE, 7: BYPASS)

Optional
int (*OEM_sys_get_image_enhance_tone) (int *value); The function gets the image enhance algorithm tone.

(browser scenario - 0: TONE_1, 1: TONE_2, 2: TONE_3) (other scenario - 0: NORMAL, 1: WARM, 2: COLD)

Optional
int (*OEM_sys_set_image_enhance_tone) (int value); The function sets the image enhance algorithm tone.

(browser scenario - 0: TONE_1, 1: TONE_2, 2: TONE_3) (other scenario - 0: NORMAL, 1: WARM, 2: COLD)

Optional
int (*OEM_sys_get_image_enhance_outdoor) (int *value); The function gets the outdoor mode of the image enhance algorithm.

(0: OUTDOOR_OFF, 1: OUTDOOR_ON)

Optional
int (*OEM_sys_set_image_enhance_outdoor) (int value); The function sets the outdoor of image enhance algorithm.

(0: OUTDOOR_OFF, 1: OUTDOOR_ON)

Optional
int (*OEM_sys_image_enhance_info) (int *value); This function reports whether the Image Quality Enhancement Algorithm is supported. Optional
int (*OEM_sys_set_display_frame_rate) (int value); The function sets the frame rate of the LCD display.

(0: OFF - 60HZ, 1: ON - 40HZ)

Optional

Light

Light interfaces provides functions to control light, brightness, and get and set brightness of LED and to control power status of LCD power.

Function Prototype Description (0: Success, Others: Failed)
int (*OEM_sys_get_backlight_max_brightness) (int index, int *value); The function gets the maximum brightness of backlight unit. Mandatory
int (*OEM_sys_get_backlight_min_brightness) (int index, int *value); The function gets the minimum brightness of backlight unit. Mandatory
int (*OEM_sys_get_backlight_brightness) (int index, int *value, int power_saving); The function gets the current brightness of backlight unit.

(0 <= value <= MAX_BACKLIGHT_BRIGHTNESS)

Mandatory
int (*OEM_sys_set_backlight_brightness) (int index, int value, int power_saving); The function sets the current brightness of backlight unit.

(0 <= value <= MAX_BACKLIGHT_BRIGHTNESS)

Mandatory
int (*OEM_sys_set_backlight_dimming) (int index, int value); The function sets the dimming status of backlight unit.

(0: Off, 1: On)

Mandatory
int (*OEM_sys_get_backlight_acl_control) (int index, int *value); The function gets the current ACL control status of backlight unit.

(0: Off, 1: On)

Optional
int (*OEM_sys_set_backlight_acl_control) (int index, int value); The function sets the current ACL control status of backlight unit.

(0: Off, 1: On)

Optional
int (*OEM_sys_get_lcd_power) (int index, int *value); The function gets the current LCD power status.

(0: Off, 1: On)

Optional
int (*OEM_sys_set_lcd_power) (int index, int value); The function sets the current LCD power status.

(0: Off, 1: On)

Optional
int (*OEM_sys_get_leds_torch_max_brightness) (int *value); The function gets the max brightness of the led torch. Optional
int (*OEM_sys_get_leds_torch_brightness) (int *value); The function gets the current brightness of the led torch.

(0 <= value <= TORCH_MAX_BRIGHTNESS)

Optional
int (*OEM_sys_set_leds_torch_brightness) (int value); The function sets the current brightness of the led torch.

(0 <= value <= TORCH_MAX_BRIGHTNESS)

Optional

Keytouch OAL Interfaces

Key and touch event OAL interfaces use standard input driver methods. These interfaces are used to get the key and touch events. The following example shows the standard input structure in the include/linux/input.h header file.

struct input_event {
    struct timeval time;
    __u16 type;
    __u16 code;
    __s32 value;
};

Battery

Battery Interfaces provide access to battery status functions to retrieve current battery status information.

Function Name Description (0: Success, Others: Failed)
int (*OEM_sys_get_battery_capacity) (int *value); The function gets the current battery capacity.

(0 %< value < 100%)

Mandatory
int (*OEM_sys_get_battery_capacity_raw) (int *value); The function gets the current battery capacity.

(0% < value < 10000%)

Mandatory
int (*OEM_sys_get_battery_charge_full) (int *value); The function gets the current battery fully charged status.

(0: Not fully charge, 1: Fully charged)

Mandatory
int (*OEM_sys_get_battery_charge_now) (int *value); The function gets the battery charging status.

(0: Not charging, 1: Charging)

Mandatory
int (*OEM_sys_get_battery_present) (int *value); The function gets the battery installation status.

(0: Not charging, 1: Charging)

Mandatory
int (*OEM_sys_get_battery_health) (int *value); The function gets the temperature status.

(0: UNKNOWN, 1: good, 2: overheat, 3: dead, 4: overvoltage, 5: unspecified, 6: cold, 7: health max)

Optional

Utility

These utility OAL interfaces monitor process, notify low memory warning, and kill the process.

Function Name Description (0: Success, Others: Failed)
int (*OEM_sys_get_memnotify_node) (char *node); The function gets the node of out of memory notification. Mandatory
int (*OEM_sys_get_memnotify_victim_task) (int *value); The function gets the pid of victim process to be killed in OOM. Mandatory
int (*OEM_sys_set_memnotify_threshold_lv1) (int value); The function sets the memory size of thershold OOM level 1. Mandatory
int (*OEM_sys_set_memnotify_threshold_lv2) (int value); The function sets the memory size of thershold OOM level 2. Mandatory
int (*OEM_sys_get_process_monitor_node) (char *node); The function gets the node that send pid of unexpected killed proccess. Mandatory
int (*OEM_sys_set_process_monitor_mp_pnp) (int value); The function sets the pid of the process regarded as a permanent process. Mandatory
int (*OEM_sys_set_process_monitor_mp_vip) (int value); The function sets the pid of the process regarded as vip process type. Mandatory

Configuration

None

Reference

Packagename: device-manager-plugin-exynos

Include file: devman_define_node_path.h

Source file: device_manager_plugin_exynos.c

PM Kernel Configuration

Power management options
[*] Power Management support
  • Linux Suspend Resume Code is located at kernel/power.
  • Generic Device/Bus suspend resume code located at drivers/base/power/.
  • Device/Bus level suspend resume code in .suspend and .resume callbacks for each device driver or bus driver.

sys interface: /sys/kernel/power/

CPU Idle

It is a generic framework for supporting software-controlled idle processor power management. It includes modular cross-platform governors that can be swapped during runtime.

[*] CPU idle PM support

The default CPU Idle governor is the menu governor and the code is located at drivers/cpuidle.

sys interface: /sys/devices/system/cpu/cpuidle/

CPU DVFS

CPU DVFS allows you to change the clock speed of CPUs on the fly. This is a nice method to save power, because the lower the CPU clock speed, the less power the CPU consumes.

[*] CPU Frequency scaling
[ ]   Enable CPUfreq debugging
<*>   CPU frequency translation statistics
[ ]     CPU frequency translation statistics details
-*-   Enable CPU tickling from drivers and users
      Default CPUfreq governor  (performance)  --->
-*-   'performance' governor
<*>   'powersave' governor
<*>   'userspace' governor for userspace frequency scaling
<*>   'ondemand' cpufreq policy governor
-*-     flexrate interface for 'ondemand' cpufreq policy governor
 (100)    flexrate's maximum duration of sampling rate override
<*>   'convervative' cpufreq governor

There are different generic CPU frequency governors, such as performance, powersave, userspace, and ondemand, to control transitions among various Operating Points. The code is located at drivers/cpufreq.

sys interface: /sys/devices/system/cpu/cpufreq/


CPU Hotplug

In addition to the above, Tizen Power management provides extra features to support dynamic CPU hotplug to reduce power consumption.

To enable this feature, select the following configuration:

-*- Support for hot-pluggable CPUs (EXPERIMENTAL)

sys interface: /sys/devices/system/cpu/

To support dynamic CPU hotplug to reduce power consumption, select the following configuration: System Type -> Support dynamic cpu hotplug ->

[*] Use Dynamic Hotplug
      Dynamic Hotplug Mechanism(PM Dynamic hotlug) --->

sys interface: /sys/module/pm_hotplug/


System OAL Kernel configuration
CONFIG_SLP_PROCESS_MON
CONFIG_INPUT
CONFIG_INPUT_MISC
CONFIG_INPUT_MOUSEDEV(Optional)
CONFIG_INPUT_KEYBOARD(Optional)
CONFIG_INPUT_TOUCHSCREEN(Optional)
CONFIG_FB
CONFIG_FB_S3C
CONFIG_BACKLIGHT_CLASS_DEVICE
CONFIG_LCD_CLASS_DEVICE
CONFIG_LCD_S6E8AA0
CONFIG_MMC
CONFIG_MMC_BLOCK
CONFIG_MMC_SDHCI_S3C
CONFIG_MMC_S3C_DEV_HSMMC*
CONFIG_USB_EXYNOS_SWITCH
CONFIG_UART_SELECT
CONFIG_VIBETONZ
CONFIG_CHARGER_MANAGER
CONFIG_PM
CONFIG_PM_SLEEP
CONFIG_JACKMON
CONFIG_CPU_FREQ
CONFIG_RTC_DRV_S3C
CONFIG_RTC_DRV_MAX8997

Sensor Framework

Sensor devices are used widely in mobile devices to enhance user experience. Most modern mobile OSs have a framework which manages sensor hardware on the platform and provides convenient API to the application.

Types of Sensors

Tizen supports individual plugin frameworks for these sensors:

Sensorframework.png

  • Accelerometer Sensor
The accelerometer sensor is used to measure the acceleration of the device. The 3-dimensional coordinate system is used to illustrate the direction of the acceleration. When a phone is moving along an axis, the acceleration is positive if it moves in a positive direction.
  • Gyroscope Sensor
A gyroscope is a device used primarily for navigation and measurement of angular velocity. Gyroscopes measure how quickly an object rotates. This rate of rotation can be measured along any of the 3 axes X, Y, and Z.
  • Proximity sensor
A proximity sensor can detect the presence of nearby objects without any physical contact. That is, it indicates if the device is close or not close to the user.
  • Motion Sensor
A motion sensor is a virtual sensor that uses the accelerometer and gyroscope sensors. Motion sensor detects snap, panning, tilt, shake, overturn, and double tap event.
  • Geomagnetic Sensor
A geomagnetic sensor indicates the strength of the geomagnetic flux density in the X, Y, and Z axes. This sensor is used to find the orientation of a body, which is a description of how it is aligned to the space it is in.
  • Light Sensor
A light sensor measures the amount of light that it receives or the surrounding light conditions. The ambient light state is measured as a step value, where 0 is very dark and 10 is bright sunlight.

Components of the Sensor Framework

The Sensor framework provides a sensor server for creating plugins and a medium through which the client applications are connected to the sensor hardware to exchange data. The sensor plugins retrieve data from sensor hardware and enable the client applications to use the data for specific requirements.

Here's the description of the sensor framework components:

Sensor Library

The application that wants to access the sensor service must communicate with the daemon through the sensor API library. An API library allows the application to access the sensor service. As shown in the below diagram, applications/middleware frameworks can have the sensor-framework client library in the process context.

Sensor Server

The sensor server is a daemon which communicates uniquely to sensor drivers in the system and dispatches sensor data to the application. The sensor server takes care of interacting with the sensor driver in hardware initialization, driver configuration, and data fetching, to manage all sensors on the platform.

Plugin Types in the Sensor Framework

Sensor plugins takes care of interacting with the sensor driver. Plug-ins process data from sensor drivers and communicate it to the sensor server. The framework has the following types of sensor plugins:

  • Processor
Active component (it has a thread) that processes data or makes events from a filter or from sensor data.
  • Filter
Passive component that converts sensor raw data to other types of data.
  • Sensor
Passive component that gets raw data from the kernel node.

Porting OAL Interface

The sensor OAL includes the processor plugin, the filter plugin, and the sensor plugin. The accelerometer sensor (accel) is taken as an example to illustrate each plugin prototype implementation. You can use the common sensor plugin (processor, filter, sensor) code in git:sensor-framework/sensor-plugin-source.

Processor Plugin

Active component (with a thread) that processes data or makes events from a filter or from sensor data.

The following code snippet shows the prototype implementation of the processor plugin.

	
class accel_processor : public cprocessor_module {
 public:
    /*define enums*/
    /*define structures*/

    accel_processor();
    virtual ~ accel_processor();

    const char *name(void);
    int id(void);
    int version(void);

    bool update_name(char *name);
    bool update_id(int id);
    bool update_version(int version);
    bool add_input(csensor_module * sensor);
    bool add_input(cfilter_module * filter);

    long value(char *port);
    long value(int id);

    cprocessor_module *create_new(void);
    void destroy(cprocessor_module * module);

    static void *working(void *inst);
    static void *stopped(void *inst);

    virtual bool start(void);
    virtual bool stop(void);

    bool add_callback_func(cmd_reg_t * param);
    bool remove_callback_func(cmd_reg_t * param);
    bool check_callback_event(cmd_reg_t * param);

    long set_cmd(int type, int property, long input_value);
    int get_property(unsigned int property_level, void *property_data);
    int get_struct_value(unsigned int struct_type, void *struct_values);

    bool waiting_for_data(unsigned long time_us, bool real_update = false);

 private:
    /* Define private data structures and functions*/
};

Prototype Description Return Value
accel_processor() Constructor, initializes all private variables. NA
virtual ~ accel_processor() Destructor, deallocates variables. NA
const char *name(void) Returns the plugin's name. Returns m_name (processor plugin name)
int id(void) Returns the plugin's ID. Returns m_id (processor plugin ID)
int version(void) Returns the plugin's version. Returns m_version (processor plugin version)
bool update_name(char *name) Updates the sensor_name. The parameter is the new processor plugin name. Returns true on success.
bool update_id(int id) Updates the ID of the plugin. The parameter is the new plugin ID. Returns true on success.
bool update_version(int version) Updates the version of the plugin. The parameter is the new plugin version. Returns true on success.
bool add_input(csensor_module * sensor) Adds a sensor module in the processor plugin. The parameter is the sensor plugin's module. Returns true on success.
bool add_input(cfilter_module * filter) Adds a filter module in the processor plugin. The parameter is the filter plugin's module. Returns true on success.
long value(int id) Gets the sensor data by port ID. The parameter is the port ID. Returns the sensor data by the port ID.
long value(char *port) Gets the sensor data by the port name. The parameter is the port name. Returns the sensor data by the port name.
cprocessor_module *create_new(void) Creates a list of processors and returns the processor module. Returns the processor module instance on success.
void destroy(cprocessor_module * module) Deletes a module in the list of processors. Returns the processor module instance on success.
static void *working(void *inst) Gets sensor data and makes event, sets the event to vconf. The parameter is the processor module. NA
static void *stopped(void *inst) Stops the loop. The parameter is the processor module. NA
virtual bool start(void) Starts the processor plugin (set the m_client for counting) . Returns true on success.
virtual bool stop(void) Stops the processor plugin (set m_client for counting). Returns true on success.
bool add_callback_func(cmd_reg_t * param) Registers the callback event. The parameter is the event parameter. Returns true on success.
bool remove_callback_func(cmd_reg_t * param) Unregisters the callback event. The parameter is the event parameter. Returns true on success.
bool check_callback_event(cmd_reg_t * param) Checks the callback event. The parameter is the event parameter. Returns true on success.
long set_cmd(int type, int property, long input_value) Sets the event or data in a sensor and returns the result or output data. The parameters are the sensor type, property or command for the sensor, and input data for the property or command. Returns output data from property or command.
int get_property(unsigned int property_level, void *property_data) Returns the sensor specification. The parameters are the desired specification and the specification data. Returns 0 on success, and a negative value on failure.
int get_struct_value(unsigned int struct_type, void *struct_values) Returns meaningful sensor data. The parameters are the desired data type and the meaningful data structure, including values. Returns 0 on success, and a negative value on failure.
cmodule *module_init(void *win, void *egl) Initializes and creates the module. Returns the created module on success, otherwise NULL.
void module_exit(cmodule *inst) Deletes the created module. NA

The following code snippets shows the accelerometer processor plugin code.

	
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <dlfcn.h>
#include <pthread.h>
#include <string.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <math.h>
#include <sys/select.h>
#include <sys/time.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>
#include <dirent.h>
#include <dlfcn.h>

#include <common.h>
#include <cobject_type.h>
#include <clist.h>
#include <cmutex.h>
#include <cmodule.h>
#include <csync.h>
#include <cworker.h>
#include <cpacket.h>
#include <csock.h>
#include <sf_common.h>

#include <csensor_module.h>
#include <cfilter_module.h>
#include <cprocessor_module.h>
#include <accel_processor.h>

#include <vconf.h>

#define ROTATION_0 0
#define ROTATION_90 90
#define ROTATION_180 180
#define ROTATION_270 270
#define ROTATION_360 360
#define ROTATION_THD 45
#define RADIAN_VALUE 57.29747
#define GRAVITY 9.80665
#define RAW_DATA_BY_MG_UNIT 1
#define G_TO_MG 1000
#define RAW_DATA_TO_G_UNIT ((float)RAW_DATA_BY_MG_UNIT/((float)1000))
#define RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT (GRAVITY * RAW_DATA_TO_G_UNIT)
#define LOW_FILTER_ALPHA 0.8
#define LOW_FILTER_ALPHA_R 0.2
#define MS_TO_US 1000

#define HORIZON_STRING_LENGTH 100
#define HORIZON_SEQ 30
#define SENSOR_NAME "accel_processor"
#define ROTATION_CB_KEY DEFAULT_SENSOR_KEY_PREFIX"10001"
#define HORIZON_CB_KEY DEFAULT_SENSOR_KEY_PREFIX"10008"
#define WAKEUP_CB_KEY DEFAULT_SENSOR_KEY_PREFIX"10010"


accel_processor::accel_processor()
: m_sensor(NULL)
, m_filter(NULL)
, m_x(-1)
, m_y(-1)
, m_z(-1)
, m_gravity_x(-1)
, m_gravity_y(-1)
, m_gravity_z(-1)
, m_curr_event(0)
, m_new_event(0)
, m_version(1)
, m_id(0x04BE)
, m_acc_theta(-1)
, m_acc_pitch(-1)
, m_client(0)
, m_work_err_count(0)
, m_rotation_cb_client(0)
, m_data_report_cb_client(0)
, m_set_horizon_cb_client(0)
, m_set_wakeup_cb_client(0)
, m_orientation_report_cb_client(0)
, m_linear_acceleration_report_cb_client(0)
, m_gravity_report_cb_client(0)
, m_fired_time(0)
, m_polling_interval_us(200000)
, m_curr_window_count(0)
, m_set_horizon_count(0)
, m_poll_counter(5)
, m_poll_max(POLL_5HZ)
{
    m_name = strdup(SENSOR_NAME);
    m_rotation_cb_key = strdup(ROTATION_CB_KEY);
    m_set_horizon_cb_key = strdup(HORIZON_CB_KEY);
    m_wakeup_cb_key = strdup(WAKEUP_CB_KEY);
    if ((!m_name) ||(!m_rotation_cb_key) || (!m_set_horizon_cb_key)) {
        free(m_name);
        m_name = NULL;
        free(m_rotation_cb_key);
        m_rotation_cb_key = NULL;
        free(m_set_horizon_cb_key);
        m_set_horizon_cb_key = NULL;
        free(m_wakeup_cb_key);
        m_wakeup_cb_key = NULL;
        throw ENOMEM;
    }

    rotation_mode[0].rotation = ROTATION_UNKNOWN;
    rotation_mode[0].rm[0] = ROTATION_UNKNOWN;
    rotation_mode[0].rm[1] = ROTATION_UNKNOWN;

    rotation_mode[1].rotation = ROTATION_HEAD_ROTATE_90;
    rotation_mode[1].rm[0] = ROTATION_LANDSCAPE_LEFT;
    rotation_mode[1].rm[1] = ROTATION_PORTRAIT_BTM;

    rotation_mode[2].rotation = ROTATION_HEAD_ROTATE_0;
    rotation_mode[2].rm[0] = ROTATION_PORTRAIT_TOP;
    rotation_mode[2].rm[1] = ROTATION_LANDSCAPE_LEFT;

    rotation_mode[3].rotation = ROTATION_HEAD_ROTATE_180;
    rotation_mode[3].rm[0] = ROTATION_PORTRAIT_BTM;
    rotation_mode[3].rm[1] = ROTATION_LANDSCAPE_RIGHT;

    rotation_mode[4].rotation = ROTATION_HEAD_ROTATE_270;
    rotation_mode[4].rm[0] = ROTATION_LANDSCAPE_RIGHT;
    rotation_mode[4].rm[1] = ROTATION_PORTRAIT_TOP;

    cprocessor_module::set_main(working, stopped, this);
}

accel_processor::~accel_processor()
{
    free(m_name);
    free(m_rotation_cb_key);
    free(m_set_horizon_cb_key);
    free(m_wakeup_cb_key);
}

bool accel_processor::add_input(csensor_module *sensor)
{
    m_sensor = sensor;

    return true;
}

bool accel_processor::add_input(cfilter_module *filter)
{
    m_filter = filter;

    return true;
}

const char *accel_processor::name(void)
{
    return m_name;
}

int accel_processor::id(void)
{
    return m_id;
}

int accel_processor::version(void)
{
    return m_version;
}

bool accel_processor::update_name(char *name)
{
    char *new_name;
    new_name = strdup(name);
    if (!new_name) {
        DbgPrint("No memory\n");

        return false;
    }

    free(m_name);
    m_name = new_name;

    return true;
}

bool accel_processor::update_id(int id)
{
    m_id = id;

    return true;
}

bool accel_processor::update_version(int version)
{
    m_version = version;

    return true;
}

cprocessor_module *accel_processor::create_new(void)
{
    return (cprocessor_module*)this;
}

void accel_processor::destroy(cprocessor_module *module)
{
    bool bstate = false;

    bstate = cmodule::del_from_list((cmodule *)module);

    if (!bstate ) {
        ERR("Destory and del_from_list fail");
        delete (accel_processor *)module;	

        return ;
    }	
}

void *accel_processor::stopped(void *inst)
{
    accel_processor *processor = (accel_processor*)inst;

    if (!processor) {
        ERR("There is no processor module instance at accel (%s)\n", __FUNCTION__ );
    }

    return (void*)NULL;
}

void *accel_processor::working(void *inst)
{	
    long status_event = 0;	
    int state;

    csensor_module *sensor;
    long x, y, z;
    double norm_z, atan_value;
    int acc_theta , acc_pitch;
    int i;
    bool rotation_on = false;
    int smart_detection_state;

    accel_processor *processor = (accel_processor*)inst;
    if (!processor) {
        ERR("There is no processor module instance at accel (%s)\n", __FUNCTION__ );
        
        return (void*)cworker::STOPPED;
    }

    if (!processor->m_sensor ) {
        ERR("Sensor is not added\n");
	
        return (void*)cworker::STOPPED;
    }

    //! Implementation dependent
    sensor = (csensor_module*)processor->m_sensor;

    if (sensor->is_data_ready(true) == false) {
        processor->lock();
        processor->m_work_err_count++;
        if (processor->m_work_err_count > 10 ) {
            processor->unlock();
            ERR("Too many error counted stop processor");

            return (void*)cworker::STOPPED;
        }
        processor->unlock();

        return (void*)cworker::STARTED;		
    }
		
    x =  sensor->value("x");
    y =  sensor->value("y");
    z =  sensor->value("z");

    processor->lock();

    if (processor->m_rotation_cb_client > 0) {
        if (processor->m_poll_counter % processor->m_poll_max != 0) {
            processor->m_poll_counter += 5;
            processor->unlock();

            return (void*)cworker::STARTED;
        }
        else
            processor->m_poll_counter = 5;

            atan_value = atan2(x,y);
            acc_theta = (int)(atan_value * (RADIAN_VALUE) + 360)%360;

            if (z * RAW_DATA_TO_G_UNIT > 1.0) {
                norm_z = 1.0;
            } 
	    else if (z * RAW_DATA_TO_G_UNIT < -1.0) {
                norm_z = -1.0;
            }
            else {
                norm_z = ((double)z * (double)RAW_DATA_TO_G_UNIT);
            }
            acc_pitch = (int)( acos(norm_z) *(RADIAN_VALUE));

            if ((acc_pitch>PITCH_MIN) && (acc_pitch<PITCH_MAX)) {
                if ((acc_theta >= ROTATION_360 - ROTATION_THD && acc_theta <= ROTATION_360 - 1) || (acc_theta >= ROTATION_0 && acc_theta <= ROTATION_0 + ROTATION_THD)) {
                    status_event = processor->rotation_mode[ROTATION_HEAD_ROTATE_0].rm[processor->m_lcd_type];
                }
                else if (acc_theta >= ROTATION_90 - ROTATION_THD && acc_theta <= ROTATION_90 + ROTATION_THD)
                {
                    status_event = processor->rotation_mode[ROTATION_HEAD_ROTATE_90].rm[processor->m_lcd_type];
                }
                else if (acc_theta >= ROTATION_180 - ROTATION_THD && acc_theta <= ROTATION_180 + ROTATION_THD)
                {
                    status_event = processor->rotation_mode[ROTATION_HEAD_ROTATE_180].rm[processor->m_lcd_type];
                }
                else if (acc_theta >= ROTATION_270 - ROTATION_THD && acc_theta <= ROTATION_270 + ROTATION_THD)
                {
                    status_event = processor->rotation_mode[ROTATION_HEAD_ROTATE_270].rm[processor->m_lcd_type];
                }		
            }

            processor->m_windowing[processor->m_curr_window_count++] = status_event;

            if (processor->m_curr_window_count == MAX_WINDOW_NUM )
                processor->m_curr_window_count = 0;

            for (i=0; i < MAX_WINDOW_NUM ; i++) {
                if (processor->m_windowing[i] == status_event)
                    rotation_on = true;
                else
                {
                    rotation_on = false;
                    break;
                }
            }

            processor->m_acc_theta = acc_theta ;
            processor->m_acc_pitch = acc_pitch ;
            processor->m_curr_event = status_event;	

            if (processor->m_new_event != status_event && rotation_on && status_event != 0) {
                if (processor->m_rotation_cb_client > 0) {
                    DBG("get_smart_detection success");
                    processor->m_new_event = status_event;
                }
                else
                {
                    DBG("event changed , set new event at key : %s , value : %d \n", processor->m_rotation_cb_key , (int)(status_event));
                    if (processor->m_rotation_cb_key) {
                        state = vconf_set_int(processor->m_rotation_cb_key, (int)(status_event));
                        if (state < 0) {
                            ERR("Fail vconf_set_int at key : %s , value : %d\n",processor->m_rotation_cb_key, (int)(status_event));
                        }
                        else
                            processor->m_new_event = status_event;
                    }
	        }
            }
        } else {
            DBG("No event changed\n");
        }
    }
	
    processor->m_x = x;
    processor->m_y = y;
    processor->m_z = z;

    //! TODO: How can I get the polling interval?
    //! TODO: When we get a polling interval, try read data in that interval :D
    processor->unlock();

    return (void*)cworker::STARTED;
}

long accel_processor::value(char *port)
{
    if (!strcasecmp(port, "acc_cod_x")) {
        return value(VALUE_ID_0);
    } else if (!strcasecmp(port, "acc_cod_y")) {
        return value(VALUE_ID_1);
    } else if (!strcasecmp(port, "acc_cod_z")) {
        return value(VALUE_ID_2);
    } else if (!strcasecmp(port, "acc_theta")) {
        return value(VALUE_ID_10);
    } else if (!strcasecmp(port, "acc_pitch")) {
        return value(VALUE_ID_11);
    } else if (!strcasecmp(port, "acc_state")) {
        return value(VALUE_ID_12);
    }	
	
    return -1;
}

long accel_processor::value(int id)
{
    if (id == VALUE_ID_0) {
        return m_x;
    } else if (id == VALUE_ID_1) {
        return m_y;
    } else if (id == VALUE_ID_2) {
        return m_z;
    } else if (id == VALUE_ID_10) {
        return m_acc_theta;
    } else if (id == VALUE_ID_11) {
        return m_acc_pitch;
    } else if (id == VALUE_ID_12) {
        return m_new_event;
    } 
	
    return -1;
}

bool accel_processor::start(void)
{
    bool ret;
    int i;

    cprocessor_module::lock();
    m_client ++;
    if (m_client > 1) {
        cprocessor_module::unlock();
        DBG("%s processor fake starting\n",m_name);

        return true;
    }

    DBG("%s processor real starting\n",m_name);

    for(i = 0 ; i < MAX_WINDOW_NUM ; i++)
        m_windowing[i] = 0;
    m_curr_window_count = 0;

    //! Before starting the processor module,
    //! We have to enable sensor
    ret = m_sensor ? m_sensor->start() : false;
    if ( ret != true ) {
        cprocessor_module::unlock();
        ERR("m_sensor start fail\n");

        return false;
    }

    cprocessor_module::start();
    cprocessor_module::unlock();

    return ret;
}

bool accel_processor::stop(void)
{
    bool ret;
    int i;

    cprocessor_module::lock();
    m_client --;
    if (m_client > 0) {
        cprocessor_module::unlock();
        DBG("%s processor fake Stopping\n",m_name);

        return true;
    }

    DBG("%s processor real Stopping\n",m_name);
	
    m_client = 0;

    for(i = 0 ; i < MAX_WINDOW_NUM ; i++)
        m_windowing[i] = 0;
    m_curr_window_count = 0;

    ret = cprocessor_module::stop();
    if (ret != true) {
        cprocessor_module::unlock();
        ERR("cprocessor_module::stop()\n");
		
        return false;
    }

    ret = m_sensor ? m_sensor->stop() : false;
    if (ret != true) {
    cprocessor_module::unlock();
    ERR("m_sensor stop fail\n");
	
    return false;
    }

    cprocessor_module::unlock();
	
    return ret;
}

bool accel_processor::add_callback_func(cmd_reg_t * param)
{
    char dummy_key[MAX_KEY_LEN];
	
    if (param->type != REG_ADD) {
        ERR("invaild cmd type !!");

        return false;
    }

    cprocessor_module::lock();
    switch (param->event_type) {
    case ACCELEROMETER_EVENT_ROTATION_CHECK:
        if ((m_rotation_cb_client < 1) || (!m_rotation_cb_key)) {
            memset(dummy_key,'\0',MAX_KEY_LEN);
            snprintf(dummy_key,(MAX_KEY_LEN-1),"%s%x",DEFAULT_SENSOR_KEY_PREFIX,param->event_type);
            if (m_rotation_cb_key) {
                free (m_rotation_cb_key);
                m_rotation_cb_key = NULL;
            }
            m_rotation_cb_key = strdup(dummy_key);
            if (!m_rotation_cb_key) {
                cprocessor_module::unlock();
                ERR("Err No memory for event key , evt_type : %x",param->event_type);

                return false;
            }
        }
        param->interval = 200;
        m_rotation_cb_client++;
        break;
    case ACCELEROMETER_EVENT_RAW_DATA_REPORT_ON_TIME:
        m_data_report_cb_client++;
        break;
    case ACCELEROMETER_EVENT_SET_HORIZON:
        m_set_horizon_cb_client++;
        break;
    case ACCELEROMETER_EVENT_ORIENTATION_DATA_REPORT_ON_TIME:
        m_orientation_report_cb_client++;
        break;
    case ACCELEROMETER_EVENT_LINEAR_ACCELERATION_DATA_REPORT_ON_TIME:
        m_linear_acceleration_report_cb_client++;
        break;
    case ACCELEROMETER_EVENT_SET_WAKEUP:
        set_cmd(ID_ACCEL, ACCELEROMETER_PROPERTY_SET_WAKEUP, 1);
        m_set_wakeup_cb_client++;
        break;
    case ACCELEROMETER_EVENT_GRAVITY_DATA_REPORT_ON_TIME:
        m_gravity_report_cb_client++;
        break;
    default:
        cprocessor_module::unlock();
        ERR("invaild event type !!");
        return false;
    }

    if (!cprocessor_module::add_interval_to_list(param->interval, m_polling_interval_us)){
        DBG("add_callback changed from interval = [%d] to [%d]",m_polling_interval_us / 1000, param->interval);
        m_polling_interval_us = cprocessor_module::norm_interval(param->interval) * MS_TO_US;
        m_poll_max = cprocessor_module::check_hz(param->interval);
        m_sensor->update_polling_interval(cprocessor_module::norm_interval(param->interval));
    }
    cprocessor_module::unlock();
    DBG("add_callback interval = [%d] param-interval = [%d]",m_polling_interval_us / 1000, param->interval);

    return true;
}

bool accel_processor::remove_callback_func(cmd_reg_t * param)
{
    int min_interval = 0;

    if ( param->type != REG_DEL ) {
        ERR("invaild cmd type !!");

        return false;
    }
    cprocessor_module::lock();
    switch ( param->event_type ) {
    case ACCELEROMETER_EVENT_ROTATION_CHECK:
        if (m_rotation_cb_client == 0) {
            cprocessor_module::unlock();
            ERR("There is no registed client !!");

            return false;
        }
        if (m_rotation_cb_client > 0)
            m_rotation_cb_client--;
        if ((m_rotation_cb_client == 0) && (m_rotation_cb_key!=NULL)) {
            free (m_rotation_cb_key);
            m_rotation_cb_key = NULL;				
        }
        param->interval = 200;
        break;
    case ACCELEROMETER_EVENT_RAW_DATA_REPORT_ON_TIME:
        if (m_data_report_cb_client > 0)
                m_data_report_cb_client--;
        break;
    case ACCELEROMETER_EVENT_SET_HORIZON:
        if (m_set_horizon_cb_client > 0)
            m_set_horizon_cb_client--;
        break;
    case ACCELEROMETER_EVENT_ORIENTATION_DATA_REPORT_ON_TIME:
        if (m_orientation_report_cb_client > 0)
            m_orientation_report_cb_client--;
        break;
    case ACCELEROMETER_EVENT_LINEAR_ACCELERATION_DATA_REPORT_ON_TIME:
        if (m_linear_acceleration_report_cb_client > 0)
            m_linear_acceleration_report_cb_client--;
        break;
    case ACCELEROMETER_EVENT_SET_WAKEUP:
        if (m_set_wakeup_cb_client > 0)
        {
            set_cmd(ID_ACCEL, ACCELEROMETER_PROPERTY_SET_WAKEUP, 0);
            m_set_wakeup_cb_client--;
        }
        break;
    case ACCELEROMETER_EVENT_GRAVITY_DATA_REPORT_ON_TIME:
        if (m_gravity_report_cb_client > 0)
            m_gravity_report_cb_client--;
        break;
    default:
        cprocessor_module::unlock();
        ERR("invaild event type !!");

        return false;
    }	

    min_interval = cprocessor_module::del_interval_to_list(param->interval, m_polling_interval_us);

    DBG("del_callback before interval = [%d]",m_polling_interval_us / 1000);
    m_polling_interval_us = cprocessor_module::norm_interval(min_interval) * MS_TO_US;
    m_poll_max = check_hz(min_interval);
    m_sensor->update_polling_interval(cprocessor_module::norm_interval(min_interval));
    cprocessor_module::unlock();

    DBG("del_callback end interval = [%d]",cprocessor_module::norm_interval(min_interval));

    return true;
}

bool accel_processor::check_callback_event(cmd_reg_t *param)
{
    if (param->type != REG_CHK) {
        ERR("invaild cmd type !!");

        return false;
    }

    switch (param->event_type) {
    case ACCELEROMETER_EVENT_ROTATION_CHECK:
    case ACCELEROMETER_EVENT_RAW_DATA_REPORT_ON_TIME:
    case ACCELEROMETER_EVENT_SET_HORIZON:
    case ACCELEROMETER_EVENT_SET_WAKEUP:
    case ACCELEROMETER_EVENT_ORIENTATION_DATA_REPORT_ON_TIME:
    case ACCELEROMETER_EVENT_LINEAR_ACCELERATION_DATA_REPORT_ON_TIME:
    case ACCELEROMETER_EVENT_GRAVITY_DATA_REPORT_ON_TIME:
        DBG("event check ok\n");
        break;
			
    default:
        ERR("invaild event type !!");

        return false;
    }	

    return true;
}

long accel_processor::set_cmd(int type , int property , long input_value)
{
    int ret = 0;

    ret = m_sensor ? m_sensor->set_cmd(type, property, input_value) : 0;
    if (ret < 0) {
        ERR("m_sensor set_cmd fail");

        return ret;
    }

    DBG("ret = [%d] property = [%d]",ret, property);

    return ret;
}

int accel_processor::get_property(unsigned int property_level , void *property_data )
{
    int result = -1;
    base_property_struct *return_property;
    return_property = (base_property_struct *)property_data;

    if (m_sensor) {
        result = m_sensor->get_property(ACCELEROMETER_BASE_DATA_SET , return_property);
        if(result == 0) {
            if (property_level == ACCELEROMETER_BASE_DATA_SET) {
                return result;
            }
            else if (property_level == ACCELEROMETER_ORIENTATION_DATA_SET)
            {
                return_property->sensor_unit_idx = IDX_UNIT_DEGREE;
                return_property->sensor_min_range = -180;
                return_property->sensor_max_range = 360;
                return_property->sensor_resolution = 1;
            }
            else if (property_level == ACCELEROMETER_LINEAR_ACCELERATION_DATA_SET)
            {
                return_property->sensor_unit_idx = IDX_UNIT_METRE_PER_SECOND_SQUARED;
                return_property->sensor_min_range = -20.0;
                return_property->sensor_max_range =  20.0;
                return_property->sensor_resolution = 0.1;
            }
            else if (property_level == ACCELEROMETER_GRAVITY_DATA_SET)
            {
                return_property->sensor_unit_idx = IDX_UNIT_METRE_PER_SECOND_SQUARED;
                return_property->sensor_min_range = -2.0;
                return_property->sensor_max_range =  2.0;
                return_property->sensor_resolution = 0.01;
            }
                else
            {
                ERR("cannot get_property from sensor\n");

                return -1;
            }

            return result;
        }
    } else {
        ERR("no m_sensor , cannot get_property from sensor\n");
    }

    return -1;
}

int accel_processor::get_struct_value(unsigned int struct_type , void *struct_values)
{
    int state;
    base_data_struct sensor_struct_data;
    base_data_struct *return_struct_data = NULL;

    state = m_sensor ? m_sensor->get_struct_value(ACCELEROMETER_BASE_DATA_SET , &sensor_struct_data) : -1;
    if (state<0) {
        ERR("Error , m_sensor get struct_data fail\n");

        return -1;
    }

    if (struct_type == ACCELEROMETER_BASE_DATA_SET) {
        return_struct_data = (base_data_struct *)struct_values;
        return_struct_data->data_accuracy = sensor_struct_data.data_accuracy;
        return_struct_data->data_unit_idx = IDX_UNIT_METRE_PER_SECOND_SQUARED;
        return_struct_data->values_num = 3;
        return_struct_data->values[0] = sensor_struct_data.values[0] * RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT;
        return_struct_data->values[1] = sensor_struct_data.values[1] * RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT;
        return_struct_data->values[2] = sensor_struct_data.values[2] * RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT;
    } else if (struct_type == ACCELEROMETER_ORIENTATION_DATA_SET) {
        return_struct_data = (base_data_struct *)struct_values;
        return_struct_data->data_accuracy = sensor_struct_data.data_accuracy;
        return_struct_data->data_unit_idx = IDX_UNIT_DEGREE;
        return_struct_data->values_num = 3;
        return_struct_data->values[0] = (int)(atan2(sensor_struct_data.values[0], sensor_struct_data.values[1]) * RADIAN_VALUE + 360) % 360;
        return_struct_data->values[1] =	(int)(atan2(sensor_struct_data.values[1], sensor_struct_data.values[2]) * RADIAN_VALUE      ) % 180;
        return_struct_data->values[2] = (int)(atan2(sensor_struct_data.values[0], sensor_struct_data.values[2]) * RADIAN_VALUE      ) % 180;

        if (return_struct_data->values[2] > 90)
            return_struct_data->values[2] = 180 - return_struct_data->values[2];
        else if (return_struct_data->values[2] < -90)
            return_struct_data->values[2] = -180 - return_struct_data->values[2];
    } else if (struct_type == ACCELEROMETER_LINEAR_ACCELERATION_DATA_SET) {
        return_struct_data = (base_data_struct *)struct_values;
        return_struct_data->data_accuracy = sensor_struct_data.data_accuracy;
        return_struct_data->data_unit_idx = IDX_UNIT_METRE_PER_SECOND_SQUARED;
        return_struct_data->values_num = 3;
        cprocessor_module::lock();
        m_gravity_x = (LOW_FILTER_ALPHA * m_gravity_x) + (LOW_FILTER_ALPHA_R * sensor_struct_data.values[0]);
        m_gravity_y = (LOW_FILTER_ALPHA * m_gravity_y) + (LOW_FILTER_ALPHA_R * sensor_struct_data.values[1]);
        m_gravity_z = (LOW_FILTER_ALPHA * m_gravity_z) + (LOW_FILTER_ALPHA_R * sensor_struct_data.values[2]);
        return_struct_data->values[0] = (sensor_struct_data.values[0] - m_gravity_x) * RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT;
        return_struct_data->values[1] = (sensor_struct_data.values[1] - m_gravity_y) * RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT;
        return_struct_data->values[2] = (sensor_struct_data.values[2] - m_gravity_z) * RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT;
        cprocessor_module::unlock();
    } else if (struct_type == ACCELEROMETER_GRAVITY_DATA_SET) {
        return_struct_data = (base_data_struct *)struct_values;
        return_struct_data->data_accuracy = sensor_struct_data.data_accuracy;
        return_struct_data->data_unit_idx = IDX_UNIT_METRE_PER_SECOND_SQUARED;
        return_struct_data->values_num = 3;
        return_struct_data->values[0] = sensor_struct_data.values[0] * RAW_DATA_TO_G_UNIT;
        return_struct_data->values[1] = sensor_struct_data.values[1] * RAW_DATA_TO_G_UNIT;
        return_struct_data->values[2] = sensor_struct_data.values[2] * RAW_DATA_TO_G_UNIT;
    } else {
        ERR("does not support stuct_type\n");

        return -1;
    }

    return 0;
}

cmodule *module_init(void *win, void *egl)
{
    accel_processor *inst;

    try {
        inst = new accel_processor();
    } catch (int ErrNo) {
        ERR("accel_processor class create fail , errno : %d , errstr : %s\n",ErrNo, strerror(ErrNo));

        return NULL;
    }

    return (cmodule*)inst;
}

void module_exit(cmodule *inst)
{
    accel_processor *sample = (accel_processor*)inst;
    delete sample;
}
//! End of a file

Sensor Plugin

A passive component that gets raw data from the kernel node.

The following code snippet shows the prototype implementation of the sensor plugin.

class caccel:public csensor_module {
 public:
    /*define enums*/
    /*define structures*/

    caccel();
    virtual ~ caccel();
    const char *name(void);
    int version(void);
    int id(void);

    bool is_data_ready(bool wait = false);
    long value(const char *port);
    long value(int id);
    bool update_name(char *name);
    bool update_version(int ver);
    bool update_id(int id);
    int port_count(void);
    const char *port(int idx);
    bool need_polling(void);
    long polling_interval(void);
    bool update_polling_interval(unsigned long val);
    int get_sensor_type(void);
    long set_cmd(int type, int property, long input_value);
    int get_property(unsigned int property_level, void *property_data);
    int get_struct_value(unsigned int struct_type, void *struct_values);
    bool calibration(int iteration);
    int check_hw_node(void);
    bool start(void);
    bool stop(void);
    void reset(void);

 private:
/* Define private data structures and functions*/
};
Prototype Description
bool is_data_ready(bool wait) When sensor data is available to be read from the sensor node, then return that status. This function waits during polling time and calls the update_value. If the wait is true, then wait during the polling interval time.
int port_count(void) Returns the port count in the sensor. For example, accelerometer sensor has X, Y, Z port. In this case, the port_count function returns 3.
const char *port(int idx) Returns the port name by the index number. When the port(0) called in the accelerometer sensor, then this function returns ‘x’.
void reset(void) Resets the sensor node.
bool start(void) / bool stop(void) Enables or disables the sensor. This is the interface for the on or off function for the sensor. It starts or stops function success, then returns true. Otherwise, it returns false.
bool need_polling(void) Announces that sensor’s data reading type is polling or interrupted. If it is true, it is polling, otherwise it is interrupted.
long polling_interval(void) Senses the need to poll data. Returns the polling interval time by ms.
bool update_polling_interval(unsigned long val) Updates polling interval by ms.
void lock(void) Locks the sensor and blocks the other component’s access.
void unlock(void) Unlocks the sensor and releases the other component's access.

The following code snippet shows the sensor plugin code for the lsm330dlc accelerometer sensor.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <dirent.h>
#include <sys/poll.h>

#include <common.h>
#include <cobject_type.h>
#include <cmutex.h>
#include <clist.h>
#include <cmodule.h>
#include <cpacket.h>
#include <csync.h>
#include <cworker.h>
#include <csock.h>
#include <sf_common.h>

#include <csensor_module.h>

#include <clsm330dlc_accel.h>
#include <sys/ioctl.h>

#define ACC_DEV_NODE "/dev/accelerometer"

/* lsm330dlc_accel_ACCEL ioctl command label */
#define LSM330DLC_ACCEL_IOCTL_BASE 'a'
#define LSM330DLC_ACCEL_IOCTL_SET_DELAY _IOW(LSM330DLC_ACCEL_IOCTL_BASE, 0, int64_t)
#define LSM330DLC_ACCEL_IOCTL_GET_DELAY _IOR(LSM330DLC_ACCEL_IOCTL_BASE, 1, int64_t)
#define LSM330DLC_ACCEL_IOCTL_READ_XYZ  _IOR(LSM330DLC_ACCEL_IOCTL_BASE, 8, struct lsm330dlc_acc)
#define LSM330DLC_ACCEL_IOCTL_SET_ENABLE _IOW(LSM330DLC_ACCEL_IOCTL_BASE, 9, int)

#define SENSOR_NAME "lsm330dlc_accel"
#define SENSOR_CHIP_NAME "LSM330DLC"
#define SENSOR_CHIP_VENDOR "ST Microelectronics"
#define WAKEUP_NODE "/sys/class/sensors/accelerometer_sensor/reactive_alert"
#define CALIBRATION_NODE "/sys/class/sensors/accelerometer_sensor/calibration"
#define CALIBRATION_FILE "/csa/sensor/accel_cal_data"
#define CALIBRATION_DIR  "/csa/sensor"

#define SENSOR_NODE_LENGTH 256
#define CHIP_NAME_LENGTH 50

#define REACTIVE_ALERT_OFF 0
#define REACTIVE_ALERT_ON 3

static const int64_t accel_delay_ns[] = {
    744047LL , /* 1344Hz */
    2500000LL , /*  400Hz */
    5000000LL , /*  200Hz */
    10000000LL , /*  100Hz */
    20000000LL , /*   50Hz */
    40000000LL , /*   25Hz */
    100000000LL , /*   10Hz */
    1000000000LL , /*    1Hz */
};


struct lsm330dlc_acc {
    int16_t x;
    int16_t y;
    int16_t z;
};

const char *clsm330dlc_accel::m_port[] = {"x", "y", "z",};

clsm330dlc_accel::clsm330dlc_accel()
: m_id(0x0000045A)
, m_version(1)
, m_polling_interval(100000)
, m_x(-1)
, m_y(-1)
, m_z(-1)
, m_fired_time(0)
, m_client(0)
, m_sensor_type(ID_ACCEL)
{
    m_name = strdup(SENSOR_NAME);
    m_wakeup_resource = strdup(WAKEUP_NODE);
    if ((!m_name) || (!m_wakeup_resource)) {
        free(m_name);
        free(m_wakeup_resource);
        throw ENOMEM;
    }

    if (check_hw_node() != 1 ) {
        free(m_name);
        free(m_wakeup_resource);
        throw ENXIO;
    }	
}

clsm330dlc_accel::~clsm330dlc_accel()
{
    free(m_name);
    free(m_wakeup_resource);
}

const char *clsm330dlc_accel::name(void)
{
    return m_name;
}

int clsm330dlc_accel::version(void)
{
    return m_version;
}

int clsm330dlc_accel::id(void)
{
    return m_version;
}

/*****************************************
  read sensor data from kernel
  can use i2c, ioctrl, fopen and fread
 ****************************************/
bool clsm330dlc_accel::update_value(void)
{
    int x;
    int y;
    int z;	
    struct lsm330dlc_acc acc_data;

    if (ioctl(accel_file_handle, LSM330DLC_ACCEL_IOCTL_READ_XYZ, &acc_data) < 0) {
        ERR("cannot read ioctl for lsm330dlc_accel\n");
        
        return false;
    } else {
        x = acc_data.x;
        y = acc_data.y;
        z = acc_data.z;
    }

    csensor_module::lock();	

    m_x = x;
    m_y = y;
    m_z = z;

    csensor_module::unlock();

    DBG("Update done raw : %d, %d, %d , out_data : %d, %d, %d\n", x,y,z,m_x, m_y, m_z);
    
    return true;
}

bool clsm330dlc_accel::is_data_ready(bool wait)
{
    bool ret = false;

    DBG("Sensor, invoked\n");

    if (wait)
    {
        unsigned long long cur_time;
        unsigned long elapsed_time;
        struct timeval sv;
        gettimeofday(&sv, NULL);
        cur_time = MICROSECONDS(sv);

        elapsed_time = (unsigned long)(cur_time - m_fired_time);

        if (elapsed_time < m_polling_interval) {
            usleep(m_polling_interval - elapsed_time);
            csensor_module::lock();
            m_fired_time = cur_time + (m_polling_interval-elapsed_time);
            csensor_module::unlock();
            ret = update_value();
        }
        else {
            csensor_module::lock();
            m_fired_time = cur_time;
            csensor_module::unlock();

            return true;
        } else {
            DBG("update_value directly");
            ret = update_value();
    }

    return ret;
}

long clsm330dlc_accel::value(const char *port)
{
    if (!strcasecmp(port, "x")) {
        return m_x;
    } else if (!strcasecmp(port, "y")) {
        return m_y;
    } else if (!strcasecmp(port, "z")) {
        return m_z;
    }

    return -1;
}

long clsm330dlc_accel::value(int id)
{
    if (id == 0) {
        return m_x;
    } else if (id == 1) {
        return m_y;
    } else if (id == 2) {
        return m_z;
    }

    return -1;
}

void clsm330dlc_accel::reset(void)
{
    return;
}

bool clsm330dlc_accel::update_name(char *name)
{
    char *new_name;
    new_name = strdup(name);
    if (!new_name) {
        DBG("No memory\n");

        return false;
    }

    free(m_name);
    m_name = new_name;
    
    return true;
}

bool clsm330dlc_accel::update_version(int version)
{
    m_version = version;
	
    return true;
}

bool clsm330dlc_accel::update_id(int id)
{
    m_id = id;
	
    return true;
}

int clsm330dlc_accel::port_count(void)
{
    return 3;
}

const char *clsm330dlc_accel::port(int idx)
{
    if (idx >= (int)(sizeof(m_port)/sizeof(const char*))) {
        return NULL;
    }

    return m_port[idx];
}

bool clsm330dlc_accel::need_polling(void)
{
    return m_polling_interval != 0;
}

long clsm330dlc_accel::polling_interval(void)
{
    return (unsigned long long)m_polling_interval /1000llu ;
}

bool clsm330dlc_accel::update_polling_interval(unsigned long val)
{
    if (val < 1)
    {
        ERR("invaild interval value");

        return false;
    }

    DBG("Update polling interval %lu\n", val);
    int64_t curr_delay_ns = val * 1000000;
    csensor_module::lock();
    m_polling_interval = (unsigned long long)val * 1000llu;
    csensor_module::unlock();

    return true;
}

bool clsm330dlc_accel::start(void)
{
    int64_t curr_delay_ns = 10000000LL;
    int sensor_enable = 1;

    m_client ++;

    if (m_client > 1) {
        return true;
    }

    if ((accel_file_handle = open(ACC_DEV_NODE, O_RDWR)) < 0) {
        ERR("lsm330dlc_accel Accel sensor node open fail\n");

    return false;
    }

    if (ioctl(accel_file_handle, LSM330DLC_ACCEL_IOCTL_SET_DELAY, &curr_delay_ns) < 0) {
        DBG("set delay fail");
        close(accel_file_handle);

        return false;
    }

    if (ioctl(accel_file_handle, LSM330DLC_ACCEL_IOCTL_SET_ENABLE, &sensor_enable) < 0)
    {
        DBG("enable sensor fail");
        close(accel_file_handle);

        return false;
    }

    return true;
}

bool clsm330dlc_accel::stop(void)
{
    int sensor_enable = 0;

    m_client --;
    if (m_client > 0) {
        DBG("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Stopping\n");
	
        return true;
    }

    if (ioctl(accel_file_handle, LSM330DLC_ACCEL_IOCTL_SET_ENABLE, &sensor_enable) < 0) {
        DBG("disable sensor fail");
        close(accel_file_handle);

        return false;
    }

    close(accel_file_handle);

    return true;
}

int clsm330dlc_accel::get_sensor_type(void)
{
    return m_sensor_type;
}

int clsm330dlc_accel::set_reactive_alert(int input)
{
    FILE *fp;

    fp = fopen(WAKEUP_NODE, "w");
    if (!fp) {
        DBG("err WAKEUP_NODE initialize\n");
        
        return -1;
    }

    fprintf(fp, "%d",input);
    fclose(fp);

    return 0;
}

long clsm330dlc_accel::set_cmd(int type , int property , long input_value)
{
    long value = -1;
    struct pollfd Events;
    int retval;
    unsigned char buff = 0;
    FILE *fp;

    if (type == m_sensor_type) {
        switch (property) {
        case ACCELEROMETER_PROPERTY_SET_CALIBRATION:				
        default:
            ERR("Invalid property_cmd\n");
            break;				
        }
    }
    else {
        ERR("Invalid sensor_type\n");		
    }

    return value;
}

/*************************************
  sensor property 
*************************************/
int clsm330dlc_accel::get_property(unsigned int property_level , void *property_data)
{
    if ((property_level & 0xFFFF) == 1) {
        base_property_struct *return_property;
        return_property = (base_property_struct *)property_data;
        return_property->sensor_unit_idx = IDX_UNIT_METRE_PER_SECOND_SQUARED;
        return_property->sensor_min_range = -20.09088;
        return_property->sensor_max_range = 19.93392;
        snprintf(return_property->sensor_name,   sizeof(return_property->sensor_name),   SENSOR_CHIP_NAME  );
        snprintf(return_property->sensor_vendor, sizeof(return_property->sensor_vendor), SENSOR_CHIP_VENDOR);
        return_property->sensor_resolution = 0.15696;

        return 0;
    } else {
        ERR("Doesnot support property_level : %d\n",property_level);

        return -1;
    }

    return -1;
}

int clsm330dlc_accel::get_struct_value(unsigned int struct_type , void *struct_values)
{
    if ((struct_type & 0xFFFF) == 0x0001) {
        base_data_struct *return_struct_value = NULL;
        return_struct_value = (base_data_struct *)struct_values;
        if (return_struct_value) {
            return_struct_value->data_accuracy = 2;
            return_struct_value->data_unit_idx = IDX_UNIT_VENDOR_UNIT;
            return_struct_value->time_stamp = m_fired_time ;
            return_struct_value->values_num = 3;
            return_struct_value->values[0] = m_x;
            return_struct_value->values[1] = m_y;
            return_struct_value->values[2] = m_z;

            return 0;
        } else {
            ERR("return struct_value point error\n");
        }

    } else {
    ERR("Does not support type , struct_type : %d \n",struct_type);		
    } 

    return -1;
}

/**************************************
  check hardware node of sensor
  read kernel information and compaere
**************************************/
int clsm330dlc_accel::check_hw_node(void)
{
    const char* orig_name = "lsm330dlc_accel";
    int find_node = 0;
    fp = fopen(name_node, "r");
    if (fp) {
        if (fscanf(fp, "%s", hw_name) < 0) {
            fclose(fp);
        if (!strcasecmp(hw_name,orig_name)) {
                return find_node;
}

cmodule *module_init(void *win, void *egl)
{
    clsm330dlc_accel *sample;

    try {
        sample = new clsm330dlc_accel();
    } catch (int ErrNo) {
        ERR("clsm330dlc_accel class create fail , errno : %d , errstr : %s\n",ErrNo, strerror(ErrNo));

        return NULL;
    }

    return (cmodule*)sample;
}

void module_exit(cmodule *inst)
{
    clsm330dlc_accel *sample = (clsm330dlc_accel*)inst;
    delete sample;
}

//! End of a file

Filter Plugin

A passive component that converts sensor raw data to other types of data.

The following code snippet shows the prototype implementation of the filter plugin.

class caccel:public csensor_module {
 public:
    /* Define enums*/
/* Define structures*/

    caccel();
    virtual ~ caccel();

    const char *name(void);
    int version(void);
    int id(void);

    bool is_data_ready(bool wait = false);

    long value(const char *port);
    long value(int id);

    bool update_name(char *name);
    bool update_version(int ver);
    bool update_id(int id);

    int port_count(void);
    const char *port(int idx);

    bool need_polling(void);
    long polling_interval(void);
    bool update_polling_interval(unsigned long val);
    int get_sensor_type(void);
    long set_cmd(int type, int property, long input_value);
    int get_property(unsigned int property_level, void *property_data);
    int get_struct_value(unsigned int struct_type, void *struct_values);

    int check_hw_node(void);

    bool start(void);
    bool stop(void);

    void reset(void);

 private:
/* Define private data structures and functions*/
}

Configuration

The Sensor Framework loads the sf_sensor.conf, sf_filter.conf, sf_processor.conf, sf_datastream.conf configuration files for loading sensor, filter, and processor plugins. All configuration files are included in the sensor-framework package.

Each configuration file supports the following fields and values:

disable=yes/no   /* Enable or disable plugin */
override=yes/no  /* If overide is yes, the ID and version are updated to the following ID and version */
path=Absolute path of a component                                                          
id=decimal       /* Plugin ID */
version=decimal  /* Plugin version */
poll=deciamal(milli second) /* Default polling interval */

Between [ and ], the names of plugin are placed. If don’t want to use the plugin, set disable to yes. If you want initialize polling interval for sensor, set poll time (ex. 100 means 100ms interval for polling)

  • Example of a sample sf_sensor.conf configuration file:
[accel_sensor]
disable=no
override=yes
path=/usr/lib/sensor_framework/libaccel.so                               
id=1111
version=1
poll=100
[geo_sensor]
disable=yes
override=yes
path=/usr/lib/sensor_framework/libgeo.so
id=1113
version=1 
poll=100
  • Example of a sample sf_processor.conf configuration file:
[accel_processor]
path=/usr/lib/sensor_framework/libaccel_processor.so
id=2114
version=1
override=yes
disable=no

[gyro_processor]
path=/usr/lib/sensor_framework/libgyro_processor.so
id=2121
version=1
override=yes
disable=no

You do not need to edit the datastream configure file.

Reference

Reference kernel configuration for sensors varies with different vendor types.

Sensor components Kernel Config Device nodes
Accelerometer CONFIG_INPUT_KR3DH /dev/input/event0/

/dev/input/event1/

/dev/input/event2/

/dev/input/event3/

/dev/input/event4/

/dev/input/event5/

Proximity CONFIG_INPUT_GP2A
Light sensor CONFIG_INPUT_GP2A
Electronic compass CONFIG_SENSORS_AK8975