Android - 改變PCM數據音量大小

 



int db = 6; // 範圍:+30(最大聲) ~ 0(原始音量) ~ -96(最小聲)Step2
private double factor = Math.pow(10, (double)db/20); // 分貝公式 y = 20 * log10(x)

// 取得 16bit 採樣率的完整數據
private short getShort(byte[] data, int start) {
return (short)((data[start] & 0xFF) | ((data[start+1] << 8) & 0xFF00));
}

/* 調整 PCM 數據音量
* pData:原始音頻數據
* nLen:原始音頻數據長度
* data2:轉換後新音頻數據
* nBitsPerSample:採樣率
* multiple:表示增益值 (需代入公式計算結果,在這裡即是 factor)
*/
public int amplifyPCMData(byte[] pData, int nLen, byte[] data2, int nBitsPerSample, float multiple)
{
int nCur = 0;
float pcmval;
if (nBitsPerSample == 16) {
short volum;
while (nCur < nLen) {
volum = getShort(pData, nCur);
// volum <<= 1;
// volum = (short)(volum * multiple);
pcmval = (volum * multiple);
if(volum < -32768)
volum = -32768;
else if(volum > 32767)
volum = 32767;
else
volum = (short)pcmval;
data2[nCur] = (byte)( volum & 0xFF);
data2[nCur+1] = (byte)((volum >> 8) & 0xFF);
nCur += 2;
}
} else if(nBitsPerSample == 8) {
byte volum;
while (nCur < nLen) {
volum = pData[nCur] & 0xFF;
pcmval = (volum * multiple);
if(volum < -127)
volum = -127;
else if(volum > 128)
volum = 128;
else
volum = (byte)(pcmval);
data2[nCur] = (byte)(volum & 0xFF);
nCur++;
}
}
return 0;
}




參考:


嵌入式系統 - gpio 相關




LED 燈號控制 (假定 LED 的 GPIO 為十進制的 34)


echo 34 > /sys/class/gpio/export // 指定控制 gpio 34
echo out > /sys/class/gpio/gpio34/direction // 指定方向 (in, out)
echo 1 > /sys/class/gpio/gpio34/value // 亮
echo 0 > /sys/class/gpio/gpio34/value // 不亮



factory reset 按鍵 (假定 GPIO 為 9)


echo 9 > /sys/class/gpio/export // 指定控制 gpio 9 (預設方向為 in,所以不用再指定方向)
cat /sys/class/gpio/gpio9/value // 0: 未按壓, 1: 已按壓



列出所有 gpio 的內容


cat /sys/kernel/debug/gpio



使用 /dev/gpio 控制範例


static int doit = 0;
#define RALINK_GPIO_ENABLE_INTP 0x08
#define RALINK_GPIO_DISABLE_INTP 0x09
#define RALINK_GPIO_REG_IRQ 0x0A
typedef struct {
unsigned int irq; //request irq pin number
pid_t pid; //process id to notify
} ralink_gpio_reg_info;
static void nvramIrqHandler(int signum)
{
if (!doit && signum == SIGUSR2) {
doit = 1;
// todo ...
}
}
int main(int argc, char **argv)
{
int fd;
ralink_gpio_reg_info info;

signal(SIGUSR1, nvramIrqHandler);
signal(SIGUSR2, nvramIrqHandler);

fd = open("/dev/gpio", O_RDONLY);
if (fd < 0) {
perror("/dev/gpio");
return -1;
}

//enable gpio interrupt
if (ioctl(fd, RALINK_GPIO_ENABLE_INTP) < 0)
goto ioctl_err;

info.pid = getpid();
info.irq = 18;

//register gpio
if (ioctl(fd, RALINK_GPIO_REG_IRQ, &info) < 0)
goto ioctl_err;

close(fd);

while(1) {
sleep(60);
}
return 0;

ioctl_err:
perror("ioctl");
close(fd);
return -1;
}



FILE *fp;
if ((fptr = fopen("/proc/gpio","r"))) { // 0:not push, 1:push
char buf[20];
fgets(buf, sizeof(buf), fptr);
sscanf(buf,"%d", &push_button);
fclose(fptr);
}



使用 /dev/mem 控制範例


int _8a110_read_bt( void)
{
int fd;
void *smc_addr,*psmc_addr;
u32 u32tmp;
u8 u8tmp;

if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
printf("open /dev/mem Error\n");

psmc_addr = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,\
fd,SMC_MAP_ADDRESS & ~MAP_MASK);

if(psmc_addr == (void *) -1)
printf("Memory mapped at address %p. Error\n", psmc_addr);

smc_addr = psmc_addr + (SMC_MAP_ADDRESS & MAP_MASK);

u32tmp = (*(volatile u32 *)(smc_addr));

*(volatile u8 *)(smc_addr + GPIO_SW_ADDRESS) = 0x01; // set Multi PIN = GPIO
write( fd, smc_addr + GPIO_SW_ADDRESS, 1);

u8tmp = (*(volatile u8 *)(smc_addr + GPIO_SW_READ));

if( munmap( psmc_addr, MAP_SIZE) == -1) {
perror( " Error un-mmapping the file");
}
close(fd);

if( u8tmp == 0x28) return 1;
else return 0;

}



int _8a110_control_led(int hl)
{
int fd;
void *smc_addr,*psmc_addr;
u32 u32tmp;

if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
printf("open /dev/mem Error\n");

psmc_addr = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,\
fd,SMC_MAP_ADDRESS & ~MAP_MASK);

if(psmc_addr == (void *) -1)
printf("Memory mapped at address %p. Error\n", psmc_addr);

smc_addr = psmc_addr + (SMC_MAP_ADDRESS & MAP_MASK);

u32tmp = (*(volatile u32 *)(smc_addr));

*(volatile u8 *)(smc_addr + PROGRAM_ADDRESS) = 0x01; // set Multi PIN = GPIO
write( fd, smc_addr + PROGRAM_ADDRESS, 1);

if (hl)
*(volatile u8 *)(smc_addr + GPIO_LED_OFFSET) = 0x40; // LED OFF
else
*(volatile u8 *)(smc_addr + GPIO_LED_OFFSET) = 0x00; // LED ON
write( fd, smc_addr + GPIO_LED_OFFSET, 1);

if( munmap( psmc_addr, MAP_SIZE) == -1) {
perror( " Error un-mmapping the file");
}
close(fd);

return 0;
}


嵌入式系統 - uboot 相關



help 命令


IPQ6018# help
? - alias for 'help'
aq_load_fw- LOAD aq-fw-binary
aq_phy_restart- Restart Aquantia phy
base - print or set address offset
bdinfo - print Board Info structure
bootelf - Boot from an ELF image in memory
bootipq - bootipq from flash device
bootm - boot application image from memory
bootp - boot image via network using BOOTP/TFTP protocol
bootvx - Boot vxWorks from an ELF image
bootz - boot Linux zImage image from memory
canary - test stack canary
chpart - change active partition
cmp - memory compare
coninfo - print console devices and information
cp - memory copy
crc32 - checksum calculation
dhcp - boot image via network using DHCP/TFTP protocol
dm - Driver model low level access
echo - echo args to console
editenv - edit environment variable
env - environment handling commands
erase - erase FLASH memory
exectzt - execute TZT

exit - exit script
false - do nothing, unsuccessfully
fdt - flattened device tree utility commands
flash - flash part_name
flash part_name load_addr file_size

flasherase- flerase part_name

flinfo - print FLASH memory information
fuseipq - fuse QFPROM registers from memory

go - start application at address 'addr'
help - print command description/usage
i2c - I2C sub-system
imxtract- extract a part of a multi-image
ipq_mdio- IPQ mdio utility commands
is_sec_boot_enabled- check secure boot fuse is enabled or not

itest - return true/false on integer compare
loop - infinite loop on address range
md - memory display
mii - MII utility commands
mm - memory modify (auto-incrementing address)
mmc - MMC sub system
mmcinfo - display MMC info
mtdparts- define flash/nand partitions
mtest - simple RAM read/write test
mw - memory write (fill)
nand - NAND sub-system
nboot - boot from NAND device
nm - memory modify (constant address)
part - disk partition related commands
pci - list and access PCI Configuration Space
ping - send ICMP ECHO_REQUEST to network host
printenv- print environment variables
protect - enable or disable FLASH write protection
reset - Perform RESET of the CPU
run - run commands in an environment variable
runmulticore- Enable and schedule secondary cores
saveenv - save environment variables to persistent storage
secure_authenticate- authenticate the signed image

setenv - set environment variables
setexpr - set environment variable as the result of eval expression
sf - SPI flash sub-system
showvar - print local hushshell variables
sleep - delay execution for some time
smeminfo- print SMEM FLASH information
source - run script from memory
test - minimal test like /bin/sh
tftpboot- boot image via network using TFTP protocol
tftpput - TFTP put command, for uploading files to a server
tftpsrv - act as a TFTP server and boot the first received file
true - do nothing, successfully
tzt - load and run tzt

uart - UART sub-system
ubi - ubi commands
usb - USB sub-system
usbboot - boot from USB device
version - print monitor, compiler and linker version



常用指令


printenv // 列印環境變數
setenv ipaddr X.X.X.X // 設定環境變數 - 自己的 ip
serenv serverip X.X.X.X // 設定環變數 - tftp server ip
saveenv // 儲存環境變數

tftpboot file.img // 從指定的 tftp server 下載 file.img
flasherase rootfs // 清空 mtd 分區名稱為 rootfs 的分區
flash rootfs // file.img 寫入 mtd 分區名稱為 rootfs 的分區 (此命令已包含清空)

nand erase [0x4000000 目的位址] [0x4000000 長度] // 清空位址內容
nand write [0x44000000 來源位址] [0x4000000 目的位址] [0x3f00000 長度] // 寫入位址內容

nand read [目的位址] [來源位址] [長度] // 讀取位址內容
tftpput [來源位址] [長度] [tftpServer的檔名] // 上傳位址內容 (需在server端先建立好檔名,並給寫入權限)

bootm 0x44000000 // 直接跳到 0x44000000 的位址進行開機
bootm // 從預設位址開機 (通常是 0x44000000)
reset // 重開機

mw [位址] [] [長度] // 設定記憶體中的值
md [位址] [長度] // 讀取記憶體中的值


讀取"裝備樹" & 顯示文字 (轉成 dts 格式)

tftpboot ipq6018-cp01-c3.dtb
fdt addr 0x44000000
fdt header
fdt printer


從 u-boot 備份 mtd 分區

kernel 的 mtd 分區訊息

[ 1.533431] 0x000000000000-0x000000180000 : "0:SBL1"
[ 1.540837] 0x000000180000-0x000000280000 : "0:MIBIB"
...
[ 1.601482] 0x000000d00000-0x000007700000 : "rootfs"


命令
setenv ipaddr X.X.X.X // 設定自己的 ip
serenv serverip X.X.X.X // 設定 tftp server 的 ip

nand read 0x44000000 0 0x180000
tftpput 0x44000000 0x180000 mtd.p1

nand read 0x44000000 0x180000 0x100000
tftpput 0x44000000 0x100000 mtd.p2

// rttofs 太大了,要分兩次
nand read 0x44000000 0xd00000 0x3000000
tftpput 0x44000000 0x3000000 mtd.p14-1
nand read 0x44000000 0x3d00000 0x3A00000
tftpput 0x44000000 0x3A00000 mtd.p14-2



在 u-boot 指定 mtd 分區範例


setenv bootargs ubi.mtd=rootfs root=mtd:ubi_rootfs rootfstype=squashfs rootwait mtdparts="spi32766.0:640k(0:SBL1)ro,64k(0:MIBIB)ro,128k(0:BOOTCONFIG)ro,128k(0:BOOTCONFIG1)ro,1472k(0:QSEE)ro,64k(0:DEVCFG)ro,128k(0:RPM)ro,64k(0:CDT)ro,64k(0:APPSBLENV),640k(0:APPSBL)ro,256k(0:ART)ro,448k(flash)ro;qcom_nand.0:64M(rootfs_1),64M(rootfs)"
saveenv


在 kernel 指定 mtd 分區範例


在 kernel/drivers/of/fdt.c Func:early_init_dt_scan_chosen 裡的 bootargs-append & strlcat 之後,加入以下代碼:

if(!strstr((char *)data, "mtdparts")) {
    //char *my_bootargs = "ubi.mtd=rootfs root=mtd:ubi_rootfs rootfstype=squashfs rootwait mtdparts=\"spi32766.0:640k(0:SBL1)ro,64k(0:MIBIB)ro,128k(0:BOOTCONFIG),128k(0:BOOTCONFIG1),1472k(0:QSEE)ro,64k(0:DEVCFG)ro,128k(0:RPM)ro,64k(0:CDT)ro,64k(0:APPSBLENV),640k(0:APPSBL)ro,256k(0:ART)ro,448k(flash)ro;qcom_nand.0:64M(rootfs_1),64M(rootfs)\" swiotlb=1 coherent_pool=2M ";
    char *my_bootargs = "console=ttyMSM0,115200n8 cnss2.bdf_pci0=0xa0 ubi.mtd=rootfs root=mtd:ubi_rootfs rootfstype=squashfs rootwait mtdparts=\"qcom_nand.0:1536k(0:SBL1)ro,1024k(0:MIBIB)ro,512k(0:BOOTCONFIG)ro,512k(0:BOOTCONFIG1)ro,3584k(0:QSEE)ro,512k(0:DEVCFG)ro,512k(0:RPM)ro,512k(0:CDT)ro,512k(0:APPSBLENV)ro,1536k(0:APPSBL)ro,512k(0:ART)ro,1024k(hwconfig)ro,1024k(swconfig)ro,106M(rootfs),512k(0:ETHPHYFW)ro,64M(image)\" swiotlb=1 coherent_pool=2M ";
    strlcpy(data, my_bootargs, min((int)strlen(my_bootargs), COMMAND_LINE_SIZE));
}

分區大小內容要自行修改
(或者修改 kernel 的 .config 參數,也可達到效果)



嵌入式系統 - ubi 相關



ubi 命令

   
ubinfo // (a tool to print UBI information.) 查資訊
ubidetach // (tool to remove UBI devices (detach MTD devices from UBI)) 卸載
ubiattach // (a tool to attach MTD device to UBI.) 加載
ubimkvol // (a tool to create UBI volumes.) 建立卷
ubirmvol // (a tool to remove UBI volumes.) 刪除卷
ubirsvol // (a tool to resize UBI volumes.) 變更卷的大小
ubiformat // (a tool to format MTD devices and flash UBI images) 重建整個ubi
ubiblock // (a tool to create/remove block device interface from UBI volumes.)
ubiupdatevol // (a tool to write data to UBI volumes.) 更新卷
ubinize // (a tool to generate UBI images.) 製作 ubi 分區檔案
ubicrc32 //
ubirename // 變更卷的名稱

 掛載 ubifs


mount -t ubifs ubi0_0 /mnt/ubi // ubi0_0, 第一個0是第幾個加載的ubi流水號, 第二個0是建立ubi檔案時的vol_id
mount -t ubifs ubi0:rootfs /mnt/ubi // ubi0:rootfs, 0是第幾個加載的ubi流水號, rootfs是建立ubi檔案時的vol_name



mtd 在 kernel 的訊息範例


[ 2.893251] nand: device found, Manufacturer ID: 0xc2, Chip ID: 0xaa
[ 2.896277] nand: ONFI 10-Compliant Macronix MX30UF2G18AC
[ 2.902682] nand: 256 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64
[ 2.915469] 16 cmdlinepart partitions found on MTD device qcom_nand.0
[ 2.918829] Creating 16 MTD partitions on "qcom_nand.0":
[ 2.925254] 0x000000000000-0x000000180000 : "0:SBL1"
[ 2.932702] 0x000000180000-0x000000280000 : "0:MIBIB"
[ 2.937205] 0x000000280000-0x000000300000 : "0:BOOTCONFIG"
[ 2.941754] 0x000000300000-0x000000380000 : "0:BOOTCONFIG1"
[ 2.947094] 0x000000380000-0x000000700000 : "0:QSEE"
[ 2.954870] 0x000000700000-0x000000780000 : "0:DEVCFG"
[ 2.957800] 0x000000780000-0x000000800000 : "0:RPM"
[ 2.962746] 0x000000800000-0x000000880000 : "0:CDT"
[ 2.967500] 0x000000880000-0x000000900000 : "0:APPSBLENV"
[ 2.972404] 0x000000900000-0x000000a80000 : "0:APPSBL"
[ 2.978693] 0x000000a80000-0x000000b00000 : "0:ART"
[ 2.982961] 0x000000b00000-0x000000c00000 : "hwconfig"
[ 2.988119] 0x000000c00000-0x000000d00000 : "swconfig"
[ 2.993344] 0x000000d00000-0x000007700000 : "rootfs"
[ 3.077346] mtd: device 13 (rootfs) set to be root filesystem
[ 3.077635] mtdsplit: no squashfs found in "rootfs"
[ 3.082091] 0x000007700000-0x000007780000 : "0:ETHPHYFW"
[ 3.087948] 0x000007780000-0x00000b780000 : "image"



使用的 Image.cfg


[kernel]
# Volume mode (other option is static)
mode=ubi
# Source image
image=arch/arm64/boot/Image.itb
vol_size=10MiB
# Volume ID in UBI image
vol_id=0
# Allow for dynamic resize
vol_type=dynamic
# Volume name
vol_name=kernel

[rootfs]
# Volume mode (other option is static)
mode=ubi
# Source image
image=rootfs.squashfs
# Volume ID in UBI image
vol_id=1
# Allow for dynamic resize
vol_type=dynamic
# Volume name
vol_name=ubi_rootfs

[config_data]
mode=ubi
# this is arbitrary, since autoresize below will use up the remaining
# free space on the mtd volume
vol_size=1KiB
vol_id=2
vol_type=dynamic
vol_name=config_data
vol_flags=autoresize



 /proc/mtd 的內容


# cat /proc/mtd
dev: size erasesize name
mtd0: 00180000 00020000 "0:SBL1"
mtd1: 00100000 00020000 "0:MIBIB"
mtd2: 00080000 00020000 "0:BOOTCONFIG"
mtd3: 00080000 00020000 "0:BOOTCONFIG1"
mtd4: 00380000 00020000 "0:QSEE"
mtd5: 00080000 00020000 "0:DEVCFG"
mtd6: 00080000 00020000 "0:RPM"
mtd7: 00080000 00020000 "0:CDT"
mtd8: 00080000 00020000 "0:APPSBLENV"
mtd9: 00180000 00020000 "0:APPSBL"
mtd10: 00080000 00020000 "0:ART"
mtd11: 00100000 00020000 "hwconfig"
mtd12: 00100000 00020000 "swconfig"
mtd13: 06a00000 00020000 "rootfs"
mtd14: 00080000 00020000 "0:ETHPHYFW"
mtd15: 04000000 00020000 "image"
mtd16: 00a0d000 0001f000 "kernel"
mtd17: 03013000 0001f000 "ubi_rootfs"
mtd18: 0273c000 0001f000 "config_data"
mtd19: 0386e000 0001f000 "rootfs_data"



手動重建ubi範例


ubidetach -f -p /dev/mtd15 // 卸載ubi
ubiformat /dev/mtd15 -y // 格式化ubi
ubiattach -p /dev/mtd15 // 加載ubi
ubimkvol /dev/ubi1 -m -N rootfs_data // 建立ubi卷
mount -t ubifs ubi1:rootfs_data /mnt/data // mount ubifs


更新ubi卷 (需要先 umount)


ubiupdatevol /dev/ubi1_0 /tmp/image.data // /tmp/image.data 寫入到第2個加載的ubivoi_id0的卷
ubiupdatevol /dev/ubi1_0 -t // 清除卷


更新整個ubi


ubiformat /dev/mtd15 -y -f /tmp/image.ubi // /tmp/image.ubi 寫入到 mtd15



ubinfo 範例


# ubinfo -d 0
ubi0
Volumes count: 3
Logical eraseblock size: 126976 bytes, 124.0 KiB
Total amount of logical eraseblocks: 848 (107675648 bytes, 102.7 MiB)
Amount of available logical eraseblocks: 0 (0 bytes)
Maximum count of volumes 128
Count of bad physical eraseblocks: 0
Count of reserved physical eraseblocks: 38
Current maximum erase counter value: 2
Minimum input/output unit size: 2048 bytes
Character device major/minor: 242:0
Present volumes: 0, 1, 2

# ubinfo -d 0 -n 0
Volume ID: 0 (on ubi0)
Type: dynamic
Alignment: 1
Size: 83 LEBs (10539008 bytes, 10.1 MiB)
State: OK
Name: kernel
Character device major/minor: 242:1

# ubinfo -d 0 -n 1
Volume ID: 1 (on ubi0)
Type: dynamic
Alignment: 1
Size: 397 LEBs (50409472 bytes, 48.1 MiB)
State: OK
Name: ubi_rootfs
Character device major/minor: 242:2

# ubinfo -d 0 -n 2
Volume ID: 2 (on ubi0)
Type: dynamic
Alignment: 1
Size: 324 LEBs (41140224 bytes, 39.2 MiB)
State: OK
Name: config_data
Character device major/minor: 242:3



※ 如果 u-boot 有自己mtd的切法,不要試著在 kernel 裡改變它。
     否則當你使用 ubiupdatevol 後,會無法開機。



附件一: Image.itb 的製作方法


// ipq6018-cp01-c3.its 檔案內容

/dts-v1/;

/ {
description = "ARM64 OpenWrt FIT (Flattened Image Tree)";
#address-cells = <1>;

images {
kernel@1 {
description = "ARM64 OpenWrt Linux-4.4.60";
data = /incbin/("Image.gz");
type = "kernel";
arch = "arm64";
os = "linux";
compression = "gzip";
load = <0x41080000>;
entry = <0x41080000>;
hash@1 {
algo = "crc32";
};
hash@2 {
algo = "sha1";
};
};

fdt@1 {
description = "ARM64 OpenWrt qcom-ipq6018-cp01-c3 device tree blob";
data = /incbin/("dts/qcom/qcom-ipq6018-cp01-c3.dtb");
type = "flat_dt";
arch = "arm64";
compression = "none";
hash@1 {
algo = "crc32";
};
hash@2 {
algo = "sha1";
};
};
};

configurations {
default = "config@cp01-c3";
config@cp01-c3 {
description = "OpenWrt";
kernel = "kernel@1";
fdt = "fdt@1";
};
};
};


mkimage -f ipq6018-cp01-c3.its Image.itb

(要先有正確的dtb、kernel 編譯出 Image.gz)
64位元的位址是:0x41080000
32位元的位址是:0x41008000


// dts & dtb 互轉
dtc -I dts -O dtb -o output.dtb ipq6018-cp01-c3.dts // dts -> dtb
dtc -I dtb -O dts -o output.dts ipq6018-cp01-c3.dtb // dtb -> dts



dumpimage -l Image.itb // 列出列表
dumpimage Image.itb -T flat_dt -p 0 -o output.1 // 從 .itb 匯出列表第一個檔案 (通常是 kernel)
dumpimage Image.itb -T flat_dt -p 1 -o output.2 // 從 .itb 匯出列表第二個檔案 (通常是 dtb)


附件二: rootfs.squashfs 的製作方法


mksquashfs4 src_dir dst_file -nopad -noappend -root-owned -comp xz -Xpreset 9 -Xe -Xlc 0 -Xlp 2 -Xpb 2 -b 256k -p '/dev d 755 0 0' -p '/dev/console c 600 0 0 5 1' -processors 1
padjffs2 dst_file 4 8 16 64 128 256
dd if=dst_file of=root.squashfs bs=2k conv=sync

讀取 src_dir 目錄,建立 root.squashfs (暫存檔案為 dst_file)

附件三:image.ubi 的製作方法


ubinize -m 2048 -p 128KiB -o Image.ubi Image.cfg


附件四:image.data 的製作方法


mkfs.ubifs -x lzo -m 2048 -e 126976 -c 466 -r ./src_dir -o dst_file

-e 的值可查詢 ubinfo -d 0 的 "Logical eraseblock size"
-c 的值可查詢 ubinfo -d 0 -n 0 的 "Size"
註:增加 -F 參數,可解決 ECC ERROR 的問題 (kernel 需要 3.0 以上)。


C - inet ntoa aton (網路轉換相關)




宣告及定義


#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int inet_aton(const char *cp, struct in_addr *inp); // 網路字串(char *cp)轉網路數值. 成功回傳1, 失敗回傳0
in_addr_t inet_addr(const char *cp); // 功能與 inet_aton 相同,但是失敗回傳的-1255.255.255.255衝突。所以改用 inet_aton
in_addr_t inet_network(const char *cp); // 功能與 inet_addr 相同,測試起來會數值會反轉

char *inet_ntoa(struct in_addr in); // 網路數值轉網路字串
struct in_addr inet_makeaddr(in_addr_t net, in_addr_t host); // net host 合併
in_addr_t inet_lnaof(struct in_addr in); // 回傳網路數值的低位元部份 (依網路位元組序)
in_addr_t inet_netof(struct in_addr in); // 回傳網路數值的高位元部份 (依網路位元組序)

// 數值定義
typedef uint32_t in_addr_t;
// 結構定義
struct in_addr {
in_addr_t s_addr;
};



範例


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char **argv) {
struct in_addr inp;
int ret;
ret = inet_aton("192.168.111.222", & inp);
printf("inet_aton => %x, %d\n", inp.s_addr, ret);
printf("inet_addr => %x\n", inet_addr("192.168.111.222"));
printf("inet_network => %x\n", inet_network("192.168.111.222"));
printf("\n");
printf("inet_ntoa => %s\n", inet_ntoa(inp));
printf("inet_lnaof => %x\n", inet_lnaof(inp));
printf("inet_netof => %x\n", inet_netof(inp));
printf("\n");
ret = inet_aton("172.16.111.222", & inp);
printf("inet_aton => %x, %d\n", inp.s_addr, ret);
printf("inet_lnaof => %x\n", inet_lnaof(inp));
printf("inet_netof => %x\n", inet_netof(inp));
printf("inet_makeaddr => %x\n", inet_makeaddr(0x1122, 0x3344).s_addr);
return 0;
}

===== 執行結果 ======================
inet_aton => de6fa8c0, 1
inet_addr => de6fa8c0
inet_network => c0a86fde

inet_ntoa => 192.168.111.222
inet_lnaof => de
inet_netof => c0a86f

inet_aton => de6f10ac, 1
inet_lnaof => 6fde
inet_netof => ac10
inet_makeaddr => 44332211



其他常用


#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong); // 用於本機序轉換到網路序
uint16_t htons(uint16_t hostshort); // 用於本機序轉換到網路序
uint32_t ntohl(uint32_t netlong); // 用於網路序轉換到本機序
uint16_t ntohs(uint16_t netshort); // 用於網路序轉換到本機序

在x86用起來就是反轉順序,如:htonl(0xaa11bb22) 執行結果為 0x22bb11aa

註:在 little-endian 上呼叫,結果會跟輸入值相同


其他範例


char *my_ipv4_broadcast(char *ip, char *netmask)
{
static char buffer[32];
in_addr_t _ip = inet_addr(ip);
in_addr_t _netmask = inet_addr(netmask);
struct in_addr _broadcast;

_broadcast.s_addr = _ip | ~_netmask;
sprintf(buffer, "%s", inet_ntoa(_broadcast));

return buffer;
}
char *my_ipv4_netid(char *ip, char *netmask)
{
static char buffer[32];
in_addr_t _ip = inet_addr(ip);
in_addr_t _netmask = inet_addr(netmask);
struct in_addr _netid;

_netid.s_addr = _ip & _netmask;
sprintf(buffer, "%s", inet_ntoa(_netid));

return buffer;
}




C - open & flock & lseek

 

open 宣告及用法


#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

flags 可代入的常用參數:
    O_RDWR (可讀可寫)
    O_WRONLY (只寫)
    O_RDONLY (唯讀)
    O_CREAT (不存在就建立)
        mode 可代入的參數:
                S_IRWXU 00700 user (file owner) has read, write, and execute permission
                S_IRUSR 00400 user has read permission
                S_IWUSR 00200 user has write permission
                S_IXUSR 00100 user has execute permission
                S_IRWXG 00070 group has read, write, and execute permission
                S_IRGRP 00040 group has read permission
                S_IWGRP 00020 group has write permission
                S_IXGRP 00010 group has execute permission
                S_IRWXO 00007 others have read, write, and execute permission
                S_IROTH 00004 others have read permission
                S_IWOTH 00002 others have write permission
                S_IXOTH 00001 others have execute permission
                According to POSIX, the effect when other bits are set in mode is unspecified. On Linux, the following bits are also honored in mode:
                S_ISUID 0004000 set-user-ID bit
                S_ISGID 0002000 set-group-ID bit (see inode(7)).
                S_ISVTX 0001000 sticky bit (see inode(7)).
    O_APPEND (以附加方式開啟)
    O_NOCTTY (這個程式不控制TTY介面)
    O_NONBLOCK (非阻塞式, 讀到檔尾回傳0, 讀失敗回傳-1並設定errnoEAGAIN)
    O_SYNC (同步相關,每次寫入都等待物理 IO 結束)

lags 可代入的其他參數:
    O_NDELAY (非阻塞式, 讀到檔尾回傳0, 讀失敗回傳0)
    O_ASYNC (同步相關, 使用信號驅動的IO)
    O_DSYNC (同步相關, 每次寫入都等待物理 IO 結束。但不含元信息, 僅保證文件內容寫入完畢)
    O_DIRECT (Direct IO 方式開啟)
    O_EXCL (檔案已存在就回傳失敗。需包含 O_CREATE 一併使用)
    O_DIRECTORY (開啟目錄,如果不是目錄會回傳失敗)
    O_NOFOLLOW (如果開啟的是 link 就回傳失敗)
    O_NOATIME(進行讀取操作時,不更新 access time)
    O_LARGEFILE (可開啟 2G 以上大檔,在 64bit 平台已是預設)
    O_CLOEXEC (執行 exec 函數族後,自動關閉此 fd)
    O_TRUNC (檔案開啟後,清空檔案內容)
    O_TMPFILE (建立臨時檔案,close後自動刪除,此時 pathname 要代入的是目錄路徑。可使用 linkat 建立檔名,造成保留效果)
        如:linkat(fd, "", AT_FDCWD, "Name", AT_EMPTY_PATH) or linkat(fd, path, AT_FDCWD, "Name", AT_SYMLINK_FOLLOW)
    O_PATH (只回傳文件描述符。回傳的fd可給close、fchdir、fstat...等使用,不可給read、write使用)

O_RDWR、O_WRONLY、O_RDONLY 這三個一定要選擇一項


flock 宣告及用法


#include <sys/file.h>

int flock(int fd, int operation);

operation 可代入參數:
    LOCK_SH (共用鎖。不需等待呼叫 LOCK_UN 也可在不同地方同時執行多次 LOCK_SH)
    LOCK_EX (獨佔鎖。先前已呼叫過 LOCK_SH or LOCK_EX 會在此等待呼叫 LOCK_UN 後,才繼續執行)
    LOCK_UN (解鎖)



lseek 宣告及用法


#include <sys/types.h>
#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

whence 可代入參數:
    SEEK_SET (從頭開始加減 offset)
    SEEK_CUR (從目前位置開始加減 offset)
    SEEK_END (從尾開始加減 offset)
    SEEK_DATA (移動到 offset 的下一個 data 的位置, 版本 3.1 後才支援)
    SEEK_HOLE (移動到 offset 的下一個 hold 的位置, 版本 3.1 後才支援)

The SEEK_HOLE and SEEK_DATA operations are supported for the following filesystems:
    * Btrfs (since Linux 3.1)
    * OCFS (since Linux 3.2)
    * XFS (since Linux 3.5)
    * ext4 (since Linux 3.8)
    * tmpfs(5) (since Linux 3.8)
    * NFS (since Linux 3.18)
    * FUSE (since Linux 4.5)



範例


#include <sys/file.h>
#include <unistd.h>

int main(int argc, char **argv) {
int fd, offset = 0;
if ((fd = open("/var/data/.hs", O_CREAT | O_RDWR | O_NOCTTY | O_NDELAY)) > 0) {
flock(fd, LOCK_EX);
sleep(10);

lseek(fd, offset, SEEK_SET);
flock(fd, LOCK_UN);
sleep(10);

close(fd);
}
return 0;
}