// ... // // , , // , /* We are disabling this code for now. */ #define GPIO_INIT_PIN_MODE(_gpio, _is_input, _value) \ { \ .gpio_nr = _gpio, \ .is_input = _is_input, \ .value = _value, \ } static struct gpio_init_pin_info init_gpio_mode_grouper_common[] = { GPIO_INIT_PIN_MODE(TEGRA_GPIO_PDD7, false, 0), GPIO_INIT_PIN_MODE(TEGRA_GPIO_PCC6, false, 0), GPIO_INIT_PIN_MODE(TEGRA_GPIO_PR0, false, 0), // . - :) GPIO_INIT_PIN_MODE(TEGRA_GPIO_PBB0, true, 0), GPIO_INIT_PIN_MODE(TEGRA_GPIO_PBB5, false, 0), }; // static __initdata struct tegra_pingroup_config grouper_pinmux_common[] = { // ... /* , GPIO_PBB0 GPIO_PBB5. O , , . */ /* CAMERA */ DEFAULT_PINMUX(CAM_MCLK, VI_ALT2, PULL_DOWN, NORMAL, INPUT), DEFAULT_PINMUX(GPIO_PCC1, RSVD1, NORMAL, NORMAL, INPUT), // //DEFAULT_PINMUX(GPIO_PBB0, RSVD1, NORMAL, NORMAL, INPUT), // : , nIRQ DEFAULT_PINMUX(GPIO_PBB0, RSVD1, PULL_UP, NORMAL, INPUT), DEFAULT_PINMUX(GPIO_PBB3, VGP3, NORMAL, NORMAL, INPUT), //DEFAULT_PINMUX(GPIO_PBB5, VGP5, NORMAL, NORMAL, INPUT), // // : , DEFAULT_PINMUX(GPIO_PBB5, VGP5, PULL_DOWN, NORMAL, OUTPUT), // ... }; // ... // // , static void __init grouper_gpio_init_configure(void) { int len; int i; struct gpio_init_pin_info *pins_info; u32 project_info = grouper_get_project_id(); if (project_info == GROUPER_PROJECT_NAKASI_3G) { len = ARRAY_SIZE(init_gpio_mode_grouper3g); pins_info = init_gpio_mode_grouper3g; } else { // - 3g, 3G len = ARRAY_SIZE(init_gpio_mode_grouper_common); pins_info = init_gpio_mode_grouper_common; } for (i = 0; i < len; ++i) { tegra_gpio_init_configure(pins_info->gpio_nr, pins_info->is_input, pins_info->value); pins_info++; } } // , pinmux` // nVidia int __init grouper_pinmux_init(void) { struct board_info board_info; u32 project_info = grouper_get_project_id(); tegra_get_board_info(&board_info); BUG_ON(board_info.board_id != BOARD_E1565); grouper_gpio_init_configure(); // tegra_pinmux_config_table(grouper_pinmux_common, ARRAY_SIZE(grouper_pinmux_common)); tegra_drive_pinmux_config_table(grouper_drive_pinmux, ARRAY_SIZE(grouper_drive_pinmux)); if (project_info == GROUPER_PROJECT_NAKASI_3G) { tegra_pinmux_config_table(pinmux_grouper3g, ARRAY_SIZE(pinmux_grouper3g)); } tegra_pinmux_config_table(unused_pins_lowpower, ARRAY_SIZE(unused_pins_lowpower)); grouper_pinmux_audio_init(); return 0; } // ...
// ... // // GPIO nIRQ // , // , , // , GPIO PWRD static const struct i2c_board_info tricky_sensor_board_info[] = { { I2C_BOARD_INFO("tricky",0x55), .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PBB0) }, }; // 2 GPIO (, ). // , // // linux/gpio static int grouper_tricky_init(void) { // tegra_gpio_enable, // int ret = 0; ret = gpio_request(TEGRA_GPIO_PBB5, "tricky_npwd"); if (ret < 0) { pr_err("Tricky: Error: cannot register GPIO_PWR_DOWN\n"); } else { ret = gpio_direction_output(TEGRA_GPIO_PBB5, true); if (ret < 0) { pr_err("Tricky: Error: cannot set GPIO_PWR_DOWN as output\n"); } else { tegra_gpio_enable(TEGRA_GPIO_PBB5); } } ret = gpio_request(TEGRA_GPIO_PBB0, "tricky_nirq"); if (ret < 0) { pr_err("Tricky: Error: cannot register GPIO_NIRQ\n"); return ret; } ret = gpio_direction_input(TEGRA_GPIO_PBB0); if (ret < 0) { gpio_free(TEGRA_GPIO_PBB0); pr_err("Tricky: Error: cannot set GPIO_NIRQ as input\n"); } else { tegra_gpio_enable(TEGRA_GPIO_PBB0); } printk("%s: Tricky OK", __FUNCTION__); return ret; } // ... // , // int __init grouper_sensors_init(void) { int err; grouper_camera_init(); #ifdef CONFIG_VIDEO_OV2710 i2c_register_board_info(2, grouper_i2c2_board_info, ARRAY_SIZE(grouper_i2c2_board_info)); #endif /* Front Camera mi1040 + */ pr_info("mi1040 i2c_register_board_info"); i2c_register_board_info(2, front_sensor_i2c2_board_info, ARRAY_SIZE(front_sensor_i2c2_board_info)); err = grouper_nct1008_init(); if (err) printk("[Error] Thermal: Configure GPIO_PCC2 as an irq fail!"); i2c_register_board_info(4, grouper_i2c4_nct1008_board_info, ARRAY_SIZE(grouper_i2c4_nct1008_board_info)); mpuirq_init(); i2c_register_board_info(2, cardhu_i2c1_board_info_al3010, ARRAY_SIZE(cardhu_i2c1_board_info_al3010)); if (GROUPER_PROJECT_BACH == grouper_get_project_id()) { i2c_register_board_info(2, cap1106_i2c1_board_info, ARRAY_SIZE(cap1106_i2c1_board_info)); } // grouper_tricky_init(); i2c_register_board_info(2/* I2C , */, tricky_sensor_board_info, ARRAY_SIZE(tricky_sensor_board_info)); return 0; } // TBD ( )
#include <linux/init.h> // Macros used to mark up functions eg __init __exit #include <linux/module.h> // Core header for loading LKMs into the kernel #include <linux/device.h> // Header to support the kernel Driver Model #include <linux/kernel.h> // Contains types, macros, functions for the kernel #include <linux/fs.h> // Header for the Linux file system support #include <linux/i2c.h> // main sensor communication protocol #include <linux/gpio.h> // sensor`s wake/sleep and new data interrupts are processed via two pins #include <linux/interrupt.h> // Support GPIO IRQ handler #include <asm/uaccess.h> // copy_to_user and copy_from_user functions #include <asm/io.h> // Access to memset() #include <linux/workqueue.h> // Make IRQ event into deferred handler task #include <linux/mutex.h> // Sync data buffer usage between IRQ-work and outer read requests #include <linux/delay.h> // Access to mdelay // /dev/tricky_temperature #define DEVICE_NAME "tricky_temperature" // #define CLASS_NAME "tricky" // ... ... // MODULE_LICENSE("GPL"); MODULE_AUTHOR("Pavel Akimov"); MODULE_DESCRIPTION("Test Linux driver for tricky sensor"); ///< modinfo MODULE_VERSION("0.1"); // , static int majorNumber; static struct class* trickyClass = NULL; static struct device* trickyDevice = NULL; // ... ... // static u8 sensor_data_buffer[I2C_DATA_SIZE] = { 0 }; // I2C struct i2c_client *tricky_i2c_client = NULL; // static int dev_open(struct inode *, struct file *); static ssize_t dev_read(struct file *, char *, size_t, loff_t *); static ssize_t dev_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param); // I2C static int tricky_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); static int tricky_i2c_remove(struct i2c_client *i2c_client); // static int set_sensor_power(u8 enabled); // I2C static int read_raw_temperatures(void); // static irq_handler_t tricky_data_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs); // static void read_data_work_handler(struct work_struct *w); // static struct workqueue_struct *wq = NULL; static DECLARE_DELAYED_WORK(read_data_work, read_data_work_handler); static struct mutex read_data_mutex; // static struct file_operations fops = { .open = dev_open, .read = dev_read, .unlocked_ioctl = dev_ioctl }; // static const struct i2c_device_id tricky_i2c_id[] = { { CLASS_NAME, 0 }, { }, // , }; MODULE_DEVICE_TABLE(i2c, tricky_i2c_id); // , static struct i2c_driver tricky_i2c_driver = { .driver = { .owner = THIS_MODULE, .name = CLASS_NAME, }, .id_table = tricky_i2c_id, .probe = tricky_i2c_probe, .remove = tricky_i2c_remove }; // i2c i2c , static int tricky_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { tricky_i2c_client = client; return 0; } // static int tricky_i2c_remove(struct i2c_client *i2c_client) { if (tricky_i2c_client != NULL) { i2c_unregister_device(tricky_i2c_client); tricky_i2c_client = NULL; } return 0; } // static int __init tricky_temperature_init(void) { int err; // Try to dynamically allocate a major number for the device -- more difficult but worth it majorNumber = register_chrdev(0, DEVICE_NAME, &fops); if (majorNumber<0){ pr_err(KERN_ALERT "Tricky failed to register a major number\n"); return majorNumber; } printk(KERN_INFO "Tricky: registered correctly with major number %d\n", majorNumber); // Register the device class trickyClass = class_create(THIS_MODULE, CLASS_NAME); if (IS_ERR(trickyClass)){ // Check for error and clean up if there is pr_err(KERN_ALERT "Failed to register device class\n"); err = PTR_ERR(trickyClass); // Correct way to return an error on a pointer goto err_char_dev; } printk(KERN_INFO "Tricky: device class registered correctly\n"); // Register the device driver trickyDevice = device_create(trickyClass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME); if (IS_ERR(trickyDevice)){ // Clean up if there is an error pr_err(KERN_ALERT "Failed to create the device\n"); err = PTR_ERR(trickyDevice); goto err_class; } printk(KERN_INFO "Tricky: device class created correctly\n"); // Made it! device was initialized // I2 , // (, board grouper sensors) probe err = i2c_add_driver(&tricky_i2c_driver); if (err < 0) { pr_err("Tricky: Error: %s: driver registration failed, error=%d\n", __func__, err); goto err_dev; } // I2C ... // IRQ callback` // , err = request_irq( i2c_client->irq, (irq_handler_t)tricky_data_irq_handler, IRQF_TRIGGER_FALLING, "tricky_gpio_handler", NULL); // no shared interrupt lines if (err < 0) { pr_err("Tricky: Error: %s: cannot register GPIO_NIRQ irq handler: Error=%d\n", __func__, err); goto err_drv; } // IRQ wq = create_singlethread_workqueue("tricky_work"); mutex_init(&read_data_mutex); printk(KERN_INFO "Tricky: initialization completed\n"); return 0; err_irq: destroy_workqueue(wq); free_irq(i2c_client->irq, NULL); err_drv: i2c_del_driver(&tricky_i2c_driver); err_dev: device_destroy(trickyClass, MKDEV(majorNumber, 0)); // remove the device class_unregister(trickyClass); // unregister the device class err_class: class_destroy(trickyClass); // remove the device class err_char_dev: unregister_chrdev(majorNumber, DEVICE_NAME); // unregister the major number return err; } // static void __exit tricky_temperature_exit(void) { if (delayed_work_pending(&read_data_work) != 0) cancel_delayed_work_sync(&read_data_work); destroy_workqueue(wq); free_irq(i2c_client->irq, NULL); i2c_del_driver(&tricky_i2c_driver); if (tricky_i2c_client != NULL) { i2c_unregister_device(tricky_i2c_client); tricky_i2c_client = NULL; } device_destroy(trickyClass, MKDEV(majorNumber, 0)); class_unregister(trickyClass); class_destroy(trickyClass); unregister_chrdev(majorNumber, DEVICE_NAME); printk(KERN_INFO "Tricky: Goodbye\n"); } static int dev_open( struct inode *node, struct file *filep) { printk(KERN_INFO "Tricky: Open the LKM!\n"); return 0; } static ssize_t dev_read( struct file *filep, char *buffer, size_t len, loff_t *offset) { int ret; // , (HAL) , if (!buffer || len != I2C_DATA_SIZE) { return -EINVAL; } mutex_lock(&read_data_mutex); ret = copy_to_user(buffer, sensor_data_buffer, I2C_DATA_SIZE); mutex_unlock(&read_data_mutex); if (ret != 0) { return -ENOMEM; } return 0; } static ssize_t dev_ioctl( struct file *file, unsigned int ioctl_num, unsigned long ioctl_param) { switch (ioctl_num) { case IOCTL_POWER: ret = set_sensor_power(ioctl_param != CMD_POWER_WAKEUP ? 1 : 0); if (ret < 0) { return ret; } break; case ... // more commands default: pr_err(KERN_INFO "Tricky: invalid command type to apply\n"); return -EINVAL; } return 0; } static int set_sensor_power(u8 enabled) { gpio_set_value(GPIO_PWR_DOWN, enabled != 0); return 0; } // I2C : (2 ) // static int read_raw_temperatures(void) { int ret; struct i2c_msg write_message; struct i2c_msg read_message; write_message.addr = I2C_SLAVE_ADDRESS; write_message.flags = 0; // plain write write_message.buf = (char*)i2c_read_temperatures_address; write_message.len = sizeof(i2c_read_temperatures_address); memset(sensor_data_buffer, 0, sizeof(sensor_data_buffer)); read_message.addr = I2C_SLAVE_ADDRESS; read_message.flags = I2C_M_RD; // plain read read_message.buf = (char*)sensor_data_buffer; read_message.len = sizeof(sensor_data_buffer); // read out data ret = i2c_transfer(tricky_i2c_client->adapter, &write_message, 1); if (ret < 0) { pr_err(KERN_INFO "Tricky: Cannot write data address. Error=%d\n", ret); return ret; } ret = i2c_transfer(tricky_i2c_client->adapter, &read_message, 1); if (ret < 0) { pr_err(KERN_INFO "Tricky: Cannot read data from the sensor. Error=%d\n", ret); return ret; } return 0; } // - // , I2C , // I2C // , , , // static irq_handler_t tricky_data_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs) { // , if (delayed_work_pending(&read_data_work) == 0) queue_delayed_work(wq, &read_data_work, msecs_to_jiffies(1)); return (irq_handler_t)IRQ_HANDLED; } // , // // ( , ) static void read_data_work_handler(struct work_struct *w) { int ret; mutex_lock(&read_data_mutex); ret = read_raw_temperatures(); mutex_unlock(&read_data_mutex); if (ret < 0) { printk(KERN_INFO "Tricky: read_data_work_handler. Ret = %d\n", ret); } } // , module_init(tricky_temperature_init); module_exit(tricky_temperature_exit);
menuconfig THERMAL tristate "Generic Thermal sysfs driver" help Generic Thermal Sysfs driver offers a generic mechanism for thermal management. Usually it's made up of one or more thermal zone and cooling device. Each thermal zone contains its own temperature, trip points, cooling devices. All platforms with ACPI thermal support can use this driver. If you want this support, you should say Y or M here. config THERMAL_HWMON bool depends on THERMAL depends on HWMON=y || HWMON=THERMAL default y config TRICKY_SENSOR default y bool prompt "Tricky temperature sensor support"
obj-$(CONFIG_THERMAL) += thermal_sys.o obj-$(CONFIG_TRICKY_SENSOR) += tricky_temperature.o
kernel/tegra/arch/arm/mach-tegra/board-grouper-pinmux.c kernel/tegra/arch/arm/mach-tegra/board-grouper-sensors.c kernel/tegra/drivers/thermal/tricky_sensor.c kernel/tegra/drivers/thermal/KConfig kernel/tegra/drivers/thermal/Makefile
It doesn’t have sampling frequency parameters. For example, you can imagine the physical sensor and the low power modes. It can only be used for an Android device; there would be no This is not an option.
There is no mechanism for data transmission. This can not be achieved.
#ifndef ANDROID_TRICKY_INTERFACE_H #define ANDROID_TRICKY_INTERFACE_H #include <stdint.h> #include <sys/cdefs.h> #include <sys/types.h> #include <hardware/hardware.h> __BEGIN_DECLS #define TRICKY_HARDWARE_MODULE_ID "tricky" struct tricky_device_t { struct hw_device_t common; int (*read_sample)(unsigned short *psynchro, short *pobj_temp, short *pntc1_temp, short *pntc2_temp, short *pntc3_temp); int (*activate)(unsigned char enabled); int (*set_mode)(unsigned char is_continuous); }; __END_DECLS #endif // ANDROID_TRICKY_INTERFACE_H
#include <errno.h> #include <cutils/log.h> #include <cutils/sockets.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <linux/i2c.h> #include <hardware/sensor_tricky_temperature.h> #define LOG_TAG "TRICKY" #define DEVICE_NAME "/dev/tricky_temperature" #define TRICKY_MODE_0 0 #define TRICKY_MODE_1 1 int fd = 0; int read_sample(unsigned short *psynchro, short *pobj_temp, short *pntc1_temp, short *pntc2_temp, short *pntc3_temp) { int ret = 0; unsigned char buffer[10]; ALOGD("HAL -- read_sample() called"); ret = read(fd, (char*)buffer, sizeof(buffer)); if (ret < 0) { ALOGE("HAL -- cannot read raw temperature data"); return -1; } if (psynchro) *psynchro = (unsigned short)(buffer[3] << 8 | buffer[2]); if (pobj_temp) *pobj_temp = (short)(buffer[1] << 8 | buffer[0]); if (pntc1_temp) *pntc1_temp = (short)(buffer[5] << 8 | buffer[4]); if (pntc2_temp) *pntc2_temp = (short)(buffer[7] << 8 | buffer[6]); if (pntc3_temp) *pntc3_temp = (short)(buffer[9] << 8 | buffer[8]); ALOGD("HAL - sample read OK"); return 0; } int activate(unsigned char enabled) { int ret = 0; ALOGD("HAL - activate(%d) called", enabled); ret = ioctl(fd, 0, enabled ? TRICKY_MODE_0 : TRICKY_MODE_1); if (ret < 0) { ALOGE("HAL - cannot write activation state"); return -1; } ALOGD("HAL - activation state written OK"); return 0; } int set_mode(unsigned char is_continuous) { int ret; ALOGD("HAL -- set_mode(%d) called", is_continuous); ret = ioctl(fd, 1, is_continuous ? TRICKY_MODE_0 : TRICKY_MODE_1); if (ret < 0) { ALOGE("HAL - cannot write mode state"); return -1; } ALOGD("HAL - mode state written OK"); return 0; } static int open_tricky(const struct hw_module_t* module, char const* name, struct hw_device_t** device) { int ret = 0; struct tricky_device_t *dev = malloc(sizeof(struct tricky_device_t)); if (dev == NULL) { ALOGE("HAL - cannot allocate memory for the device"); return -ENOMEM; } else { memset(dev, 0, sizeof(*dev)); } ALOGD("HAL - openHAL() called"); dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 0; dev->common.module = (struct hw_module_t*)module; dev->read_sample = read_sample; dev->activate = activate; dev->set_mode = set_mode; *device = (struct hw_device_t*) dev; fd = open(DEVICE_NAME, O_RDWR); if (fd <= 0) { ALOGE("HAL - cannot open device driver"); return -1; } ALOGD("HAL - has been initialized"); return 0; } static struct hw_module_methods_t tricky_module_methods = { .open = open_tricky }; struct hw_module_t HAL_MODULE_INFO_SYM = { .tag = HARDWARE_MODULE_TAG, .version_major = 1, .version_minor = 0, .id = TRICKY_HARDWARE_MODULE_ID, .name = "Tricky HAL Module", .author = "Pavel Akimov", .methods = &tricky_module_methods, };
# LOCAL_PATH := $(call my-dir) # .mk , # # , LOCAL_PATH include $(CLEAR_VARS) LOCAL_PRELINK_MODULE := false # , LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw # LOCAL_SHARED_LIBRARIES := liblog libcutils libhardware # , LOCAL_SRC_FILES := sensor_tricky_temperature.c # LOCAL_MODULE := techartmsjdts.default LOCAL_MODULE_TAGS := debug include $(BUILD_SHARED_LIBRARY)
hardware_modules := gralloc hwcomposer audio nfc nfc-nci local_time \ power usbaudio audio_remote_submix camera consumerir tricky include $(call all-named-subdir-makefiles,$(hardware_modules))
hardware/libhardware/include/hardware/sensor_tricky_temperature.h hardware/libhardware/modules/Android.mk hardware/libhardware/modules/tricky/sensor_tricky_temperature.c hardware/libhardware/modules/tricky/Android.mk
frameworks\base\core\java\android\app\ContextImpl.java frameworks\base\core\java\android\content\Context.java frameworks\base\core\java\android\hardware\temperature\ITrickyService.aidl frameworks\base\core\java\android\hardware\temperature\TrickyTemperatureData.aidl frameworks\base\core\java\android\hardware\temperature\TrickyTemperatureData.java frameworks\base\core\java\android\hardware\temperature\TrickyManager.java frameworks\base\services\java\com\android\server\temperature\TrickyService.java frameworks\base\services\java\com\android\server\SystemServer.java frameworks\base\services\jni\Android.mk frameworks\base\services\jni\com_android_server_temperature_TrickyService.cpp frameworks\base\services\jni\onload.cpp frameworks\base\Android.mk
// LOG_TAG #define LOG_TAG "TRICKY" #include "jni.h" #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" #include <utils/misc.h> #include <utils/Log.h> #include <hardware/hardware.h> #include <hardware/sensor_tricky_temperature.h> #include <stdio.h> // , , // , Android namespace android { static jlong init_native(JNIEnv *env, jobject clazz) { int err; hw_module_t* module; tricky_device_t* dev = NULL; // HAL // , hw // , // HAL ".default" - ( // - HAL, ) err = hw_get_module(TRICKY_HARDWARE_MODULE_ID, (hw_module_t const**)&module); if (err == 0) { err = module->methods->open(module, "", ((hw_device_t**) &dev)); if (err != 0) { ALOGE("init_native: cannot open device module: %d", err); return -1; } } else { ALOGE("init_native: cannot get device module: %d", err); return 0; } ALOGD("init_native: start ok"); // Java return (jlong)dev; } // static void finalize_native(JNIEnv *env, jobject clazz, jlong ptr) { tricky_device_t* dev = (tricky_device_t*)ptr; if (dev == NULL) { ALOGE("finalize_native: invalid device pointer"); return; } free(dev); ALOGD("finalize_native: finalized ok"); } // HAL // C++ TrickyTemperatureData static jobject read_sample_native(JNIEnv *env, jobject clazz, jlong ptr) { tricky_device_t* dev = (tricky_device_t*)ptr; int ret = 0; unsigned short synchro = 0; short obj_temp = 0; short ntc1_temp = 0; short ntc2_temp = 0; short ntc3_temp = 0; if (dev == NULL) { ALOGE("read_sample_native: invalid device pointer"); return (jobject)NULL; } ret = dev->read_sample(&synchro, &obj_temp, &ntc1_temp, &ntc2_temp, &ntc3_temp); if (ret < 0) { ALOGE("read_sample_native: Cannot read TrickyTemperatureData"); return (jobject)NULL; } // , // android.hardware.temperature.TrickyTemperatureData jclass c = env->FindClass("android/hardware/temperature/TrickyTemperatureData"); if (c == 0) { ALOGE("read_sample_native: Find Class TrickyTemperatureData Failed"); return (jobject)NULL; } // ( ) jmethodID cnstrctr = env->GetMethodID(c, "<init>", "()V"); if (cnstrctr == 0) { ALOGE("read_sample_native: Find constructor TrickyTemperatureData Failed"); return (jobject)NULL; } // ID . , , , getter` setter` jfieldID synchroField = env->GetFieldID(c, "synchro", "I"); jfieldID objTempField = env->GetFieldID(c, "objectTemperature", "I"); jfieldID ntc1TempField = env->GetFieldID(c, "ntc1Temperature", "I"); jfieldID ntc2TempField = env->GetFieldID(c, "ntc2Temperature", "I"); jfieldID ntc3TempField = env->GetFieldID(c, "ntc3Temperature", "I"); if (synchroField == 0 || objTempField == 0 || ntc1TempField == 0 || ntc2TempField == 0 || ntc3TempField == 0) { ALOGE("read_sample_native: cannot get fields of resulting object"); return (jobject)NULL; } // jobject jdtsData = env->NewObject(c, cnstrctr); env->SetIntField(jdtsData, synchroField, (jint)synchro); env->SetIntField(jdtsData, objTempField, (jint)obj_temp); env->SetIntField(jdtsData, ntc1TempField, (jint)ntc1_temp); env->SetIntField(jdtsData, ntc2TempField, (jint)ntc2_temp); env->SetIntField(jdtsData, ntc3TempField, (jint)ntc3_temp); ALOGD("read_sample_native: read ok"); return jdtsData; } // // JNI static JNINativeMethod method_table[] = { { "init_native", "()J", (void*)init_native }, { "finalize_native", "(J)V", (void*)finalize_native }, { "read_sample_native", "(J)Landroid/hardware/temperature/TrickyTemperatureData;", (void*)read_sample_native }, { "activate_native", "(JZ)Z", (void*)activate_native }, { "set_mode_native", "(JZ)Z", (void*)set_mode_native}, }; // onload.cpp, // system server int register_android_server_JdtsService(JNIEnv *env) { ALOGD("register_android_server_JdtsService"); return jniRegisterNativeMethods( env, "com/android/server/temperature/JdtsService", method_table, NELEM(method_table)); }; };
// ... #include "JNIHelp.h" #include "jni.h" #include "utils/Log.h" #include "utils/misc.h" namespace android { // ... int register_android_server_JdtsService(JNIEnv* env); }; using namespace android; extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) { JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { ALOGE("GetEnv failed!"); return result; } ALOG_ASSERT(env, "Could not retrieve the env!"); // ... register_android_server_JdtsService(env); return JNI_VERSION_1_4; }
package android.hardware.temperature; parcelable TrickyTemperatureData;
package android.hardware.temperature; import android.os.Parcel; import android.os.Parcelable; /** {@hide} */ public final class TrickyTemperatureData implements Parcelable { public int synchro; public int objectTemperature; public int ntc1Temperature; public int ntc2Temperature; public int ntc3Temperature; public static final Parcelable.Creator<TrickyTemperatureData> CREATOR = new Parcelable.Creator<TrickyTemperatureData>() { public TrickyTemperatureData createFromParcel(Parcel in) { return new TrickyTemperatureData(in); } public TrickyTemperatureData[] newArray(int size) { return new TrickyTemperatureData[size]; } }; public TrickyTemperatureData() { } private TrickyTemperatureData(Parcel in) { readFromParcel(in); } @Override public void writeToParcel(Parcel out, int flags) { out.writeInt(synchro); out.writeInt(objectTemperature); out.writeInt(ntc1Temperature); out.writeInt(ntc2Temperature); out.writeInt(ntc3Temperature); } public void readFromParcel(Parcel in) { synchro = in.readInt(); objectTemperature = in.readInt(); ntc1Temperature = in.readInt(); ntc2Temperature = in.readInt(); ntc3Temperature = in.readInt(); } @Override public int describeContents() { return 0; } }
// frameworks\base\core\java\android\content\Context.java /** * @hide */ public static final String TRICKY_SERVICE = "android.service.tricky.ITrickyService";
// frameworks\base\services\java\com\android\server\SystemServer.java // initAndLoop ... try { Slog.e(TAG, "Tricky Service"); trickyService = new TrickyService(context); ServiceManager.addService(Context.TRICKY_SERVICE, trickyService); } catch (Throwable e) { Slog.e(TAG, "Failure starting TrickyService", e); }
//frameworks\base\core\java\android\app\ContextImpl.java registerService(TRICKY_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { IBinder iBinder = ServiceManager.getService(Context.TRICKY_SERVICE); return new TrickyManager(ITrickyService.Stub.asInterface(iBinder)); }});
private static int sNextPerContextServiceCacheIndex = 0; // .. fetcher map private static void registerService(String serviceName, ServiceFetcher fetcher) { if (!(fetcher instanceof StaticServiceFetcher)) { fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++; } SYSTEM_SERVICE_MAP.put(serviceName, fetcher); } // , getSystemService // ... @Override public Object getSystemService(String name) { ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name); return fetcher == null ? null : fetcher.getService(this); }
#(device/asus/grouper/init.grouper.rc) # ... on post-fs-data # ... # tricky temperature sensor # / system # root` chmod 0660 /sys/class/tricky/tricky_temperature/dev chown system system /sys/class/tricky/tricky_temperature/dev
# device/asus/grouper/ueventd.grouper.rc /dev/tricky_temperature 0660 system system
##################################### # , # . # , . # (te_macros) # tricky_service_domain(domain) # Allow a base set of permissions common across Android daemons. define(`tricky_service_domain', ` init_daemon_domain($1) # Allow using binder and performing IPC to system services. binder_use($1) binder_service($1) # Allow access to files in /proc. # Fixes denials like: # avc: denied { read } for pid=1267 comm="peripheralman" name="misc" dev="proc" # ino=4026531967 scontext=u:r:peripheralman:s0 # tcontext=u:object_r:proc:s0 tclass=file permissive=0 allow $1 proc:file r_file_perms; allow $1 tricky_service:service_manager find; # Cut down on spam. dontaudit $1 kernel:system module_request; ') ##################################### # , , # # (tricky_service.te) type tricky_service, domain; type tricky_service_exec, exec_type, file_type; tricky_service_domain(tricky_service) ##################################### # , system manager # (service.te) type tricky_service, service_manager_type; # , # "tricky_service" . # SELinux https://source.android.com/security/selinux/ ##################################### # (service_contexts) android.service.jdtstemperature.IJdstsService u:object_r:tricky_service:s0 ##################################### # . # . # (device.te) type tricky_device, dev_type, mlstrustedobject; ##################################### # # (file_contexts) /dev/tricky_temperature u:object_r:tricky_device:s0 ##################################### # ( , , # "bootanim" # ) #(bootanim.te) allow bootanim tricky_device:chr_file rw_file_perms; ##################################### # , , SystemServer system apps # (system_server.te) allow system_server tricky_device:chr_file rw_file_perms; ##################################### # (system_app.te) allow system_app tricky_device:chr_file rw_file_perms;
package com.android.trickydemo; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.Switch; import android.widget.TextView; import android.hardware.temperature.*; public class MainActivity extends Activity { private final String TAG = "TrickyDemo"; private final int POLLING_PERIOD_MS = 200; private TrickyManager mServiceManager = null; private TrickyTemperatureData mSensorData = null; private GaugeView mGaugeObj; private GaugeView mGaugeNtc1; private GaugeView mGaugeNtc2; private GaugeView mGaugeNtc3; private TextView mTextSynchro; private ImageView mIrqImage; private TextView mTextObj; private TextView mTextNtc1; private TextView mTextNtc2; private TextView mTextNtc3; // all temperatures are .2 points precision values in degrees Celsius final private Object mDataSync = new Object(); private boolean mMeasModeUpdateRequired; // set up when user switches between measurement modes and queues I2C expander command // to switch the mode private boolean mIsContinuousMode; // continuous mode (power is always on, no control) // burst mode (every cycle power on, read and power off required) private boolean mPowerState; private boolean mPowerUpdateRequired; private Thread mCommThread = null; private boolean mIsRunning = true; // the communication thread goes on unless onDestroy method is called @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // enforce the sensor to switch into continuous mode on startup mPowerUpdateRequired = true; mPowerState = true; mMeasModeUpdateRequired = true; mIsContinuousMode = true; mIrqImage = (ImageView) findViewById(R.id.image_led_irq); mGaugeObj = (GaugeView) findViewById(R.id.gauge_view_obj); mGaugeNtc1 = (GaugeView) findViewById(R.id.gauge_view_ntc1); mGaugeNtc2 = (GaugeView) findViewById(R.id.gauge_view_ntc2); mGaugeNtc3 = (GaugeView) findViewById(R.id.gauge_view_ntc3); mTextSynchro = (TextView) findViewById(R.id.text_synchro); mTextObj = (TextView) findViewById(R.id.text_obj); mTextNtc1 = (TextView) findViewById(R.id.text_ntc1); mTextNtc2 = (TextView) findViewById(R.id.text_ntc2); mTextNtc3 = (TextView) findViewById(R.id.text_ntc3); Switch switch_mode = (Switch) findViewById(R.id.switch1); switch_mode.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { synchronized (mDataSync) { mIsContinuousMode = isChecked; mMeasModeUpdateRequired = true; } } }); Switch switch_power = (Switch) findViewById(R.id.switch_power); switch_power.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { synchronized (mDataSync) { mPowerState = isChecked; mPowerUpdateRequired = true; } } }); switch_power.setChecked(true); // power is on by default mServiceManager = (TrickyManager) getSystemService(TRICKY_SERVICE); mCommThread = new Thread() { @Override public void run() { while(mIsRunning) { synchronized (mDataSync) { if (mPowerUpdateRequired) { if (mServiceManager.activate(mPowerState)) { mPowerUpdateRequired = false; } else { Log.w(TAG, "Cannot update power state"); } } if (mMeasModeUpdateRequired) { if (mServiceManager.setMode(mIsContinuousMode)) { mMeasModeUpdateRequired = false; } else { Log.w(TAG, "Cannot update measurement mode"); } } } mSensorData = mServiceManager.readSample(); if (mSensorData != null) { updateUI(); } else { updateNonIRQUI(); } try { Thread.sleep(POLLING_PERIOD_MS); } catch (InterruptedException e) { e.printStackTrace(); } } } }; mCommThread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { e.printStackTrace(); } }); mCommThread.start(); } @Override protected void onDestroy() { super.onDestroy(); try { mCommThread.join(POLLING_PERIOD_MS * 2); } catch (InterruptedException e) { e.printStackTrace(); } } private void updateUI() { runOnUiThread(new Runnable() { public void run() { float obj_temp = mSensorData.objectTemperature / 100.F; float ntc1_temp = mSensorData.ntc1Temperature / 100.F; float ntc2_temp = mSensorData.ntc2Temperature / 100.F; float ntc3_temp = mSensorData.ntc3Temperature / 100.F; String s_obj = String.format("%.2f °C", obj_temp); String s_ntc1 = String.format("%.2f °C", ntc1_temp); String s_ntc2 = String.format("%.2f °C", ntc2_temp); String s_ntc3 = String.format("%.2f °C", ntc3_temp); String s_synchro = String.format("Synchro = %d", mSensorData.synchro); mGaugeObj.setTargetValue(obj_temp); mTextObj.setText(s_obj); mGaugeNtc1.setTargetValue(ntc1_temp); mTextNtc1.setText(s_ntc1); mGaugeNtc2.setTargetValue(ntc2_temp); mTextNtc2.setText(s_ntc2); mGaugeNtc3.setTargetValue(ntc3_temp); mTextNtc3.setText(s_ntc3); mTextSynchro.setText(s_synchro); mIrqImage.setImageDrawable(getResources().getDrawable(R.drawable.led_green_hi)); Log.d(TAG, s_synchro + "Obj = " + s_obj + " NTC1 = " + s_ntc1 + " NTC2 = " + s_ntc2 + " NTC3 = " + s_ntc3); } }); } private void updateNonIRQUI() { runOnUiThread(new Runnable() { public void run() { mIrqImage.setImageDrawable(getResources().getDrawable(R.drawable.led_green_md)); } }); } }
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_RESOURCE_FILES := $(addprefix $(LOCAL_PATH)/, res) LOCAL_PACKAGE_NAME := TrickyDemo LOCAL_CERTIFICATE := platform LOCAL_STATIC_JAVA_LIBRARIES := android-support-core-utils-api24 include $(BUILD_PACKAGE)
git clone https://android.googlesource.com/kernel/tegra.git -b android-tegra3-grouper-3.1-kitkat-mr2
mkdir arm-eabi-4.6 cd arm-eabi-4.6 git init git clone https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/
ARCH=arm SUBARCH=arm CROSS_COMPILE=<path_to_arm_eabi-4.6>/arm-eabi-4.6/bin/arm-eabi- make tegra3_android_defconfig ARCH=arm SUBARCH=arm CROSS_COMPILE=<path_to_arm_eabi-4.6>/arm-eabi-4.6/bin/arm-eabi- make menuconfig ARCH=arm SUBARCH=arm CROSS_COMPILE=<path_to_arm_eabi-4.6>/arm-eabi-4.6/bin/arm-eabi- make -j4 zImage
repo init -u https://android.googlesource.com/platform/manifest -b android-4.4.4_r2 cd .repo repo sync
https://dl.google.com/dl/android/aosp/asus-grouper-ktu84p-b12ce5f7.tgz https://dl.google.com/dl/android/aosp/broadcom-grouper-ktu84p-646d5a68.tgz https://dl.google.com/dl/android/aosp/elan-grouper-ktu84p-742223b3.tgz https://dl.google.com/dl/android/aosp/invensense-grouper-ktu84p-724c855a.tgz https://dl.google.com/dl/android/aosp/nvidia-grouper-ktu84p-e6d581dc.tgz https://dl.google.com/dl/android/aosp/nxp-grouper-ktu84p-27abae08.tgz https://dl.google.com/dl/android/aosp/widevine-grouper-ktu84p-57b01f77.tgz
tar -xvf asus-grouper-ktu84p-b12ce5f7.tgz tar -xvf broadcom-grouper-ktu84p-646d5a68.tgz tar -xvf elan-grouper-ktu84p-742223b3.tgz tar -xvf invensense-grouper-ktu84p-724c855a.tgz tar -xvf nvidia-grouper-ktu84p-e6d581dc.tgz tar -xvf nxp-grouper-ktu84p-27abae08.tgz tar -xvf widevine-grouper-ktu84p-57b01f77.tgz rm *.tgz ./extract-asus-grouper.sh ./extract-broadcom-grouper.sh ./extract-elan-grouper.sh ./extract-invensense-grouper.sh ./extract-nvidia-grouper.sh ./extract-nxp-grouper.sh ./extract-widevine-grouper.sh
mkdir nexus cd nexus make clobber ( ) . build/envsetup.sh lunch aosp_grouper-userdebug make -j4
make clobber
require board=grouper require version-bootloader=4.23
sudo apt-get install abootimg abootimg --create boot.img -k zImage -r ramdisk.img
adb reboot bootloader ( , usb adb)
, , .
fastboot devices
fastboot oem unlock fastboot erase boot fastboot erase cache fastboot erase recovery fastboot erase system fastboot erase userdata fastboot -2 update image.zip
Source: https://habr.com/ru/post/326640/
All Articles