2016/4/28

android . SeekBar -- 中間起始

這是github 上的 project: https://github.com/vashisthg/StartPointSeekBar

他自己寫的 seekbar widget.

project 包含 widget library 和 demo project

使用時只要library project 就可以。


Android Studio 的 project 中,使用這個 library 的方法:
  • File -- New -- Module , 出現新 Dialog
  • Dialog 中出現很多 item, 選 'Import Gradle Project',然後 Next
  • Source Directory 選到 StartPointSeekBar/Library
  • 要給名稱,.,就沿用 library 好了
這樣在 專案中就會出現一個 library folder

使用:

在 layout xml 中首先要加入:
    xmlns:custom="http://schemas.android.com/apk/res-auto"
例如..
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

然後就可以在 xml 中加入 這個 seekbar 了..
    <com.vashisthg.startpointseekbar.StartPointSeekBar
        android:id="@+id/seek_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        custom:minValue="-40.0"
        custom:maxValue="+40.0"
       />


使用的 app build.gradle 的 dependency 要加上:
compile project(':library')

要是在 gradle-experimental 的話,要大幅度修改:
apply plugin: 'com.android.model.library'

model {
    android {
        compileSdkVersion = 23
        buildToolsVersion = "23.0.3"

        defaultConfig.with {
            minSdkVersion.apiLevel = 21
            targetSdkVersion.apiLevel = 23
            versionCode = 2
            versionName = "1.2"
        }
    }

    android.buildTypes {
        release {
            minifyEnabled = false
            proguardFiles.add(file('proguard-android.txt'))
        }
    }
}

dependencies {
    compile 'com.android.support:appcompat-v7:23.3.0'
    compile fileTree(dir: 'libs', include: ['*.jar'])
}

Progress Change Handler 跟一般 Seekbar 一樣..
        StartPointSeekBar seekBar = (StartPointSeekBar) findViewById(R.id.seek_bar);
        seekBar.setOnSeekBarChangeListener(new StartPointSeekBar.OnSeekBarChangeListener() {
            @Override
            public void onOnSeekBarValueChange(StartPointSeekBar bar, double value) {
                Log.d(LOGTAG, "seekbar value:" + value);
            }
        });


        // setting progress on your own
        seekBar.setProgress(+20);
    }

2016/4/20

read permission without 'show'

開機出現這個 message:
Attribute aabubu_addr: read permission without 'show'


這個的出處是:driver/base/core.c
int device_create_file(struct device *dev,
                       const struct device_attribute *attr)
{
        int error = 0;

        if (dev) {
                WARN(((attr->attr.mode & S_IWUGO) && !attr->store),
                        "Attribute %s: write permission without 'store'\n",
                        attr->attr.name);
                WARN(((attr->attr.mode & S_IRUGO) && !attr->show),
                        "Attribute %s: read permission without 'show'\n",
                        attr->attr.name);
                error = sysfs_create_file(&dev->kobj, &attr->attr);
        }

        return error;
}
所以是 createfile 時,給了 S_IRUGO 屬性,但是沒有實做 show function

找到 driver attr 屬性:
只有..
static DEVICE_ATTR(aabubu_addr, 0666, NULL, aabubu_addr_store);
果然,沒有實做 aabubu_addr_show

所以修改 addribure, 把 0666 改 0222 就 OK 了。

2016/4/18

TabLayout

ref: http://www.truiton.com/2015/06/android-tabs-example-fragments-viewpager/

原來 tab 是手動做出來的。

再看 http://givemepass.blogspot.tw/2015/10/tablayout.html
這個也是 step by step: http://givemepass-blog.logdown.com/posts/288943-how-to-use-tablayout

原來是 android support library 新增加 actionbar 元件。

Support Library 要額外download, 會放在 extra/ 下。

裡面有這些 features

不僅提供舊OS能有新 interface 的 api support, 同時也有新增加的 feature

根據你的 OS 版本不同,要用的內容也不一樣

要用的話,除了要download, 還要修改 build.gradle, 加入
compile 'com.android.support:design:23.2.1
-- 開啟 SDK Manager 來看裝的是那一版。


根據上面兩個 ref link, 合併在一起: https://github.com/checko/TabLayout

原來TabLayout 是主要元件。
所以 main layout 上要擺一個 TabLayout (android.support.design.widget.TabLayout)
然後還需要一個區域:ViewPager (android.support.v4.view.ViewPager)

這個 ViewPager 就是用來讓 TabLayout 根據click 和滑動變更內容的區域。
TabLayout 基本上只負責 顯示 title, 反應 click/swipe 來變更 ViewPager 內容。
不管ViewPager 裡面的動作。

負責反應click, swipe 的是 TabLayout.setOnTabSelectedListener()
負責 swipe , 因為動作在ViewPager, 所以是 ViewPager.addOnPageChangeListener()

然後把 ViewPager 和每一個 page 內容 (layout) 連在一起的是 PagerAdapter 這個 class
要繼承這個 class, 實做 instantiateItem(..,int position ) 時,根據 position 把page 內容(layout)生出來。


在 ViewPager 李的每個 view 裡面的 widget (view), 只有用那個 view 才access 得到。
舉例來說,page 2 李有一個 TextView,
要用
view = getLayoutInflater().inflate(R.layout.page_2, container, false);
mTextView = (TextView) view.findValueById(R.id.tvppp);
在 MainActivity 的 OnCreate 裡,access 不到。

2016/4/15

git svn , 把 git project 丟到 svn 上

git svn clone https://my-srver/svnproject
cd svnproject
git checkout git-svn
git remote add local ~/mylocal/gitproject
git fetch local
git pull local master
git svn dcommit
比較奇怪的動作是 git checkout git-svn這個隱含的動作。
之後,對 master 做dcommit 動作都會update到 svn server
..但是用 git commit 只會 update local git repo.

2016/4/12

  • cpu_dai : cpu 端的裝置,像 I2S, ESAI
  • codec_dai : 就是 codec, 像 CS42888 和 WM8962

snd_soc_ops, 放在 snd_soc_dai_link , 他又是在 snd_soc_card:
snd_soc_card {
  snd_soc_dai_link {
     snd_soc_ops {
        .startup
        ,hw_params
     } ops
  } dai_link
}

2016/4/11

Device Driver , kernel boot.

Device Driver
  Device Tree and Open Firmware Support
    Support for device tree in /proc
module_platform_driver(imx_wm8962_driver);
include/linux/platform_device.h
/* module_platform_driver() - Helper macro for drivers that don't do
 * anything special in module init/exit.  This eliminates a lot of
 * boilerplate.  Each module may only use this macro once, and
 * calling it replaces module_init() and module_exit()
 */
#define module_platform_driver(__platform_driver) \
        module_driver(__platform_driver, platform_driver_register, \
                        platform_driver_unregister)

/* module_platform_driver_probe() - Helper macro for drivers that don't do
 * anything special in module init/exit.  This eliminates a lot of
 * boilerplate.  Each module may only use this macro once, and
 * calling it replaces module_init() and module_exit()
 */

include/linux/device.h
/**
 * module_driver() - Helper macro for drivers that don't do anything
 * special in module init/exit. This eliminates a lot of boilerplate.
 * Each module may only use this macro once, and calling it replaces
 * module_init() and module_exit().
 *
 * @__driver: driver name
 * @__register: register function for this driver type
 * @__unregister: unregister function for this driver type
 * @...: Additional arguments to be passed to __register and __unregister.
 *
 * Use this macro to construct bus specific macros for registering
 * drivers, and do not use it on its own.
 */
#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
        return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
        __unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);

所以是 call platform_driver_register(imx_wm8962_driver)

./drivers/base/platform.c:541:EXPORT_SYMBOL_GPL(platform_driver_register);
/**
 * platform_driver_register - register a driver for platform-level devices
 * @drv: platform driver structure
 */
int platform_driver_register(struct platform_driver *drv)
{
        drv->driver.bus = &platform_bus_type;
        if (drv->probe)
                drv->driver.probe = platform_drv_probe;
        if (drv->remove)
                drv->driver.remove = platform_drv_remove;
        if (drv->shutdown)
                drv->driver.shutdown = platform_drv_shutdown;

        return driver_register(&drv->driver);
}
EXPORT_SYMBOL_GPL(platform_driver_register);

至於要call 到 XXX_probe( ), 有一堆要檢查,主要是確認 platform driver 跟 platform data 有 match
match 的方式有很多種,有 bus, 有 name, 還有用 of_device (也就是 dtd) 內的 compatible 字串比較,

新版 driver 好像把所有 driver 都賦予一個 bus, 非 bus 的就給 platform 這個 'bus'

code 都在 driver/base/bus.c, dd.c, platform.c 和 driver/of/base.c

base.c:
static
const struct of_device_id *__of_match_node(const struct of_device_id *matches,
                                           const struct device_node *node)
{
        if (!matches)
                return NULL;

        while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
                int match = 1;
                if (matches->name[0])
                        match &= node->name
                                && !strcmp(matches->name, node->name);
                if (matches->type[0])
                        match &= node->type
                                && !strcmp(matches->type, node->type);
                if (matches->compatible[0])
                        match &= __of_device_is_compatible(node,
                                                           matches->compatible);
                if (match)
                        return matches;
                matches++;
        }
        return NULL;
}

compatible 的比較:
/** Checks if the given "compat" string matches one of the strings in
 * the device's "compatible" property
 */
static int __of_device_is_compatible(const struct device_node *device,
                                     const char *compat)
{
        const char* cp;
        int cplen, l;

        cp = __of_get_property(device, "compatible", &cplen);
        if (cp == NULL)
                return 0;
        while (cplen > 0) {
                if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
                        return 1;
                l = strlen(cp) + 1;
                cp += l;
                cplen -= l;
        }

        return 0;
}

2016/4/7

imx6 sabresd soud, ssi, audmux dtd

sabresd

imx6dl-sabresd.dts:
  
  imx6qdl.dtsi:
    ssi1.2.3  "fsl.imx6q-ssi","fsl-imx21-ssi"
    audmux    "fsl,imx6q-audmux","fsl,imx31-audmux"
    iomuxc
      pinctrl_audmux_1 (AUD4)
      pinctrl_audmux_2 (AUD3)
      pinctrl_audmux_3 (AUD5)
  
  imx6qdl-sabresd.dtsi:
    sound ssi2       "fsl,imx6q-sabresd-wm8962","fsl,imx-audio-wm8962"
    ssi2 i2s-slave
    audmux pinctrl_audmux_2
 
大概相關的幾個 node


driver code 相關

實際設定 AUDMUX 的地方在 sound/soc/fsl/imx-wm8962.c:
static int imx_wm8962_probe(struct platform_device *pdev)
{
       .....
       .....

        of_property_read_u32(np, "mux-int-port", &int_port);
        of_property_read_u32(np, "mux-ext-port", &ext_port);
        
        int_port--;
        ext_port--;
        ret = imx_audmux_v2_configure_port(int_port,
                        IMX_AUDMUX_V2_PTCR_SYN |
                        IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
                        IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
                        IMX_AUDMUX_V2_PTCR_TFSDIR |
                        IMX_AUDMUX_V2_PTCR_TCLKDIR,
                        IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
       ....


所以要看這個drver ("imx-audio-wm8962") 的 dtb..
imx6qdl-sabresd.dtsi
        sound {
                compatible = "fsl,imx6q-sabresd-wm8962",
                           "fsl,imx-audio-wm8962";
                model = "wm8962-audio";
                cpu-dai = <&ssi2>;
                audio-codec = <&codec>;
                audio-routing =
                        "Headphone Jack", "HPOUTL",
                        "Headphone Jack", "HPOUTR",
                        "Ext Spk", "SPKOUTL",
                        "Ext Spk", "SPKOUTR",
                        "MICBIAS", "AMIC",
                        "IN3R", "MICBIAS",
                        "DMIC", "MICBIAS",
                        "DMICDAT", "DMIC";
                mux-int-port = <2>;
                mux-ext-port = <3>;
                hp-det-gpios = <&gpio7 8 1>;
                mic-det-gpios = <&gpio1 9 1>;
        };
有 mux-int-port, mux-ext-port 兩個 value

cpu-dai 是 ssi2 ,所以mux-int-port 就是 2
audmux 用的是 pinctrl_audmux_2:
&audmux {
        pinctrl-names = "default"; 
        pinctrl-0 = <&pinctrl_audmux_2>;
        status = "okay";
};
這個 pinctrl 就是..
                pinctrl_audmux_2: audmux-2 {
                        fsl,pins = <
                                MX6QDL_PAD_CSI0_DAT7__AUD3_RXD  0x130b0
                                MX6QDL_PAD_CSI0_DAT4__AUD3_TXC  0x130b0
                                MX6QDL_PAD_CSI0_DAT5__AUD3_TXD  0x110b0
                                MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0
                        >;
                }; 
對應 AUD3, 所以 mux-ext-port 是 3

imx6 ssi & audmux

Chap 9.11 Audio subsystem
Chap 16.1 Digital Audio Multuplexer

  • SSI-1.2.3
  • AUDMUX
  • ESAI
  • SPDIF
  • ASRC
  • MLB
IOMUX 也要 config


SSI

SSI 三組,輸出不是直接到 chip pin腳。
是接到 AUDMUX, 再由 AUDMUX 的接腳輸出。

SSI 有以下模式:
  • SSI normal
  • SSI network
  • I2S
  • AC-97

SSI 有 T/R FIFO 和 DMA
SSI1.2.3 可以有個別的clk..個別的 stream 內容。


AUDMUX

audmux 是 routing 用。
有三個 internal port 和 4 個 external port

internal port 直接接到 SSI1.2.3, 不可以變更。
所以 imx6 的 IOMUX pinout 只看到 AUD3.4.5.6
-- 根據 datasheet 的圖,internal 是 AUD1.2.7 -- 大概internal 的第 3 組是後來才加的。

2016/4/6

Android Auto HeadUnit -- XDA

XDA 上有人reverse eng 了 android auto protocol. 寫了一個 headunit app:
http://forum.xda-developers.com/general/paid-software/android-4-1-headunit-android-auto-t3125252

Android Auto 的使用方式是:
  • Android Auto Headunit (也就是車用主機) -- 裝這個 app 就可以
  • 手機要裝 Android Auto App, 這只有在 support 的國家才找得到,不然就只有download apk 自己裝。http://www.apkmirror.com/apk/google-inc/android-auto/
  • HeadUnit 要有 usb host 功能,用 usb cable 連 android 手機和 Headunit
  • 手機要 disable usb debug mode, 開啟 Android Auto app
  • Headunit 會出現 usb permission dialog, 確認與許
第一次連線,手機會 download 一些 supoort 的 android auto app, 所以要有網路連線

* 跟 usb 連線有很大關係,所以用短一點的線,如果失敗,多插拔幾次。

2016/4/1

imx6 CLKO

imx6 提供兩個 clock output: CLKO1, CLKO2

CLKO1 可以選擇 GPIO0 做 clk output
CLKO2 可以選擇 GPIO3 做 clk output

CLKO1.2 的控制 register 在 CCM_CCOSR (offset 0x60)

對照 kernel source : clk-imx6q.c
在 source code 李,叫 cko1, cko2
        clk[cko1]         = imx_clk_gate("cko1",           "cko1_podf",         base + 0x60, 7);
        clk[cko2]         = imx_clk_gate("cko2",           "cko2_podf",         base + 0x60, 24);
        ....
        clk[cko1_podf]        = imx_clk_divider("cko1_podf",        "cko1_sel",          base + 0x60, 4,  3);
        clk[cko2_podf]        = imx_clk_divider("cko2_podf",        "cko2_sel",          base + 0x60, 21, 3);
        ....
        clk[cko1_sel]         = imx_clk_mux("cko1_sel",         base + 0x60, 0,  4, cko1_sels,         ARRAY_SIZE(cko1_sels));
        clk[cko2_sel]         = imx_clk_mux("cko2_sel",         base + 0x60, 16, 5, cko2_sels,         ARRAY_SIZE(cko2_sels));
        ....

clk 是 struct clk

clk 軟體模型,依照一般 clk 的設置,叫下面的名子。:
  • clk source : parent, mux (imx_clk_mux)
  • divider : divider (imx_clk_divider)
  • enable/disable : gate (imx_clk_gate)
對照宣告的時候,後面的數字就是 register 的 offset, bit-shift , bit-width
拿 gate 來看,對照 datasheet, CCM_CCOSR:

  • bit 24: CLKO2_EN : enable/disable CLKO2
  • bit 21-23 : CLKO2_DIV : divider by 1,2,3,4...8
  • bit 16-20 : CLKO2_SEL : clko2 的 clk src
  • bit 7 : CLKO1_EN
  • bit 4-6 : CLKO1_DIV
  • bit 0-3 : CLKO1_SEL
可以對照看上面code 的宣告。

然後,因為這三個類型的操作不太相同,所以要為每個類型寫一個 operatio function.
各是:clk-gate2.c, clk-fixup-div.c, clk-fixup-mix.c

以 gate 來說。
implement imx_clk_gate 的code 在 clk-gate2.c
static struct clk_ops clk_gate2_ops = {
        .enable = clk_gate2_enable,
        .disable = clk_gate2_disable,
        .is_enabled = clk_gate2_is_enabled,
};
主要就是要實做這三個 gate 的 function.
enable/disable 最後 就是...
static void clk_gate2_do_hardware(struct clk_gate2 *gate, bool enable)
{
        u32 reg;

        reg = readl(gate->reg);
        if (enable)
                reg |= CCM_CCGR_FULL_ENABLE << gate->bit_idx;
        else
                reg &= ~(CCM_CCGR_FULL_ENABLE << gate->bit_idx);
        writel(reg, gate->reg);
}

統一的 clk interface 在 driver/clk/clk.c
呼叫 clk_enable( ) 就會:
static int __clk_enable(struct clk *clk)
{
        int ret = 0;

        if (!clk)
                return 0;

        if (WARN_ON(clk->prepare_count == 0))
                return -ESHUTDOWN;

        if (clk->enable_count == 0) {
                ret = __clk_enable(clk->parent);

                if (ret)
                        return ret;

                if (clk->ops->enable) {
                        ret = clk->ops->enable(clk->hw);
                        if (ret) {
                                __clk_disable(clk->parent);
                                return ret;
                        }
                }
        }

        clk->enable_count++;
        return 0;
}

-- 另外,一般用 clk_prepare_enable( )

所以,一定要 call 過 enable( ), 那個 clock 才會動。