# 演示如何从共享内存中读取数据

## 说明
这里示例可以演示如何从xieneng_can 中共享的点表数据

每个设备一个共享文件,每个共享文件是 0xfff*2(一个寄存器2字节)

PATH定义"/tmp/shm/" + CAN port | term_addr

port 恒定为 0

term_addr 定义范围0~N ,0代表总控 1~N代表主控

地址传入的地址按照BMSer内部通讯协议地址直接映射

> 共享内存的文件路径再 "/tmp/shm/0/* "下

## 测试1
```bash
ipcs
```
返回内容
```log
------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x00437802 0          root       600        8192       2
0x00437805 32769      root       600        8192       2
0x00437803 65538      root       600        8192       2
0x00437804 98307      root       600        8192       2
0x00437806 131076     root       600        8192       2
0x00437807 163845     root       600        8192       2
0x00437808 196614     root       600        8192       2
0x00437809 229383     root       600        8192       2
0x0043780a 262152     root       600        8192       2
0x0043780b 294921     root       600        8192       2
0x0043780c 327690     root       600        8192       2
0x0043780d 360459     root       600        8192       2
0x0043780e 393228     root       600        8192       2
0x0043780f 425997     root       600        8192       2
0x00437810 458766     root       600        8192       2
0x00437811 491535     root       600        8192       2
0x00437812 524304     root       600        8192       2
0x00437801 557073     root       600        8192       2
0x00437800 589842     root       600        8192       2
0x00437814 622611     root       600        8192       0
0x140e0888 655380     root       600        8192       0
```

## 测试2
在电脑上,使用交叉编辑工具链编译如下
```bash
arm-openwrt-linux-gcc shmrw.c -g -o shmrw
```
拷贝到目标主板并执行  
参数1:0-N  共享文件id 0 总控 1-N主控 
参数2:192  查询主控 0xC0(192)寄存器,这个寄存器对应是总压
参数3:W/R  读写标志,可选参数,模式R

```bash
scp ghzhang@192.168.22.104:tmp/read .;./read 1 192
# 返回数据
#/tmp/shm/0/1  [00c0]=63552(f840)
#/tmp/shm/0/1  [00c0]=63552(f840)
```

```C
//文件 shmrw.c
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h> 
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

// #define IPCKEY 0x437800

int main(int argc, char *argv[])
{
    int addr;
    unsigned short *m_data;
    int id;
    int length = 0x1000*2;
    int shm_id, i;
    key_t key;
    char rw[10]="R";
    if (argc <= 2)
    {
        fprintf(stderr, "usage: %s slave_id addr [W]|[R]\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    id = atoi(argv[1]);
    addr = atoi(argv[2]);
    fprintf(stderr, "argc%d\n", argc);
    if (argc > 3 && strlen(argv[3]) > 0)
        strcpy(rw,argv[3]);  

    char pathname[30];
    strcpy(pathname, "/tmp");
    #ifdef IPCKEY
        key = 0x437800 | id;
    #else
        key = ftok(pathname, id);
    #endif

    

    if (key == -1)
    {
        perror("ftok error");
        return -1;
    }
    printf("key=%d\n", key);

    printf("[%s] [%s] %d %d\n",rw,"R",strlen(rw),(strncmp(rw,"R",1) == 0));
    if(strncmp(rw,"R",1) == 0)
    {
        shm_id = shmget(key, 0, 0);
        if (shm_id == -1)
        {
            perror("shmget error");
            return -1;
        }
        printf("shm_id=%d\n", shm_id);
        m_data = (unsigned short *)shmat(shm_id, NULL, 0);
        if(m_data == NULL) return 0;
        while (1)
        {
            int value = 0;
            char *p = (char *)&m_data[addr];
            value = (p[0]<<8) + p[1];
            fprintf(stderr, "%s  [%04x]=%d(%04x)\n", argv[1], addr, value, value);
            sleep(1);
        }
    }else if(strncmp(rw,"W",1) == 0)
    {
        uint16_t count = 0;
        shm_id=shmget(key,length,IPC_CREAT|IPC_EXCL|0600); 
        if(shm_id==-1 && errno == EEXIST) {
            shm_id=shmget(key,length,0); 
        }
        printf("shm_id=%d\n", shm_id);
        m_data = (unsigned short *)shmat(shm_id, NULL, 0);
        if(m_data == NULL) return 0;
        while (1)
        {
            count++;
            uint16_t value = (count>>8) + ((count&0xff)<<8);
            char *p = (char *)&m_data[addr];
            memcpy(p,&value,sizeof(value));
            sleep(1);
        }
    }else
    {
        return -1;
    }



    if (shmdt(m_data) == -1)
    {
        perror("detach error");
        return -1;
    }
    return 0;
}
```
> 目前我们使用ftok产生key 

## 测试3
可以通过'require"shmem"'添加lua包

shmem.connect(1) :连接地址码=1的地址空间(主控1)

shmem.shmget(1,0xc0,2) :访问地址码=1的地址空间,寄存器0x0c,长度2字节(不是寄存器个数)

```bash
scp ghzhang@192.168.22.104:openwrt_lora/feeds/lnxall_package/hmi4racks/script/sharemem.lua .;lua sharemem.lua

# 返回数据
#/tmp/shm/0/1
#addr:0xc0=16632
#addr:0xc0=16632
#addr:0xc0=16632
```

```lua
require "log"
require "sys"
require "utils"
require "patch"
require "pack"
require "bit"
local siganl = require 'posix.signal'
local syswait = require 'posix.sys.wait'
local unistd = require 'posix.unistd'
local lpack=require("lua_pack")
require"shmem"

local function main(nodes_cfg,sn)
    siganl.signal(siganl.SIGKILL,handler)
    siganl.signal(siganl.SIGHUP,handler)
    sys.taskInit(function()
        print(shmem.connect(1))
        while true do
            -- 等待RTC就绪
            sys.wait(1000)
            local out = shmem.shmget(1,0xc0,2)
            local out2 = shmem.shmsingle(1,0xc0)
            _,v = bunpack(out,">S")
            print(string.format("addr:0xc0=%d %d",v,out2))
        end
    end)
  
    --启动系统框架
    sys.init(0, 0)
    sys.run()
end

main(arg[1],arg[2])


```