AM335x启动盘制作脚本分析


#!/bin/sh
#-----------------------------------------------------------
# 指定目标目标存储器
#destination="/dev/mmcblk1"
destination="/dev/sdb"
#-----------------------------------------------------------
# 清空目标存储器 (1M * 16 = 16MB),其实可以省去
dd if=/dev/zero of=${destination} bs=1M count=16
#-----------------------------------------------------------
# 第1步:存储器分区,一共7个分区(重要,实际上并不需要这么多分区)
# 参数格式:起始位置,分区容量,分区类型
# 
# 起始位置:如果未指定,则为第1个可用的柱面
# 分区容量:单位由--unit参数定义
# 分区类型:L:Linux,S: Swap, E:扩展分区
#
#,,E 表示剩余的磁盘全部划为扩展分区
#,,L 将剩余的扩展分区全部划成逻辑分区
#
#--DOS DOS兼容性
#--force 强制执行
#--unit 指定单位:必须是S,C,B,M的一种

LC_ALL=C sfdisk --force --DOS --sectors 63 --heads 255 --unit M "${destination}" <<-__EOF__
    ,32,0xe,*
    ,16,0xe
    ,256,L
    ,,E
    ,256,L
    ,256,L
    ,256,L
    ,,L
__EOF__
sync
#-----------------------------------------------------------
# 格式化各分区
umount ${destination}*

mkfs.vfat -n boot    ${destination}1
mkfs.vfat -n env     ${destination}2
mkfs.ext4 -L rootfs1 ${destination}3
mkfs.ext4 -L rootfs2 ${destination}5
mkfs.ext4 -L app1    ${destination}6
mkfs.ext4 -L update  ${destination}7
mkfs.ext4 -L data    ${destination}8
sync
#-----------------------------------------------------------

#!/bin/sh
destination=sdc

echo "Copy Files to TF Card."
#
#-------------------------------------------------
# 创建挂载磁盘用的目录(如果存在的话,由跳过)
if [ ! -d /mnt/uboot ]; then
    mkdir /mnt/uboot
fi

if [ ! -d /mnt/env ]; then
    mkdir /mnt/env
fi

if [ ! -d /mnt/opt ]; then
    mkdir /mnt/opt
fi

if [ $? -gt 0 ]; then
    exit
fi

#-------------------------------------------------
# 挂载磁盘分区
umount /dev/${destination}* > /dev/null 2>&1
mount  /dev/${destination}1 /mnt/uboot > /dev/null 2>&1
mount  /dev/${destination}2 /mnt/env > /dev/null 2>&1
mount  /dev/${destination}6 /mnt/opt > /dev/null 2>&1
#
if [ $? -gt 0 ]; then
    exit
fi
echo 'mount device done'
#-------------------------------------------------
echo "======== 1. Create Uboot =================="
# 解压文件至uboot分区
tar zxvf uboot.tgz -C /mnt/uboot/
echo $?
sync
#-------------------------------------------------
# 删除环境变量
rm -rf /mnt/env/*
sync
#-------------------------------------------------
echo "======== 2. Create sys-ext-lib ============"
# 复制系统库
rm -rf /mnt/opt/*
tar zxvf sys-ext-lib.tgz -C /mnt/opt/
sync
#-------------------------------------------------
# 复制安装包至指定位置,用于进入系统后进行安装操作
echo "======== 3. Copy Kernel lib and App ======="
if [ ! -d /mnt/opt/all ]; then
    mkdir /mnt/opt/all   
fi
rm -rf /mnt/opt/all/*

cp  uboot.tgz sys-ext-lib.tgz /mnt/opt/all/

if [ -e app.tgz ]; then
    cp app.tgz /mnt/opt/all/
fi

sync
#-------------------------------------------------
umount /dev/${destination}* > /dev/null 2>&1

echo "======== 4. Finished ======================"

- 阅读全文 -

Linux应用程序--UDP广播与多播(组播)


程序猿问科比:你为什么这么成功?
科比:你知道洛杉矶早晨4点钟是什么样子吗?
程序猿:知道,一般那个时候我刚刚下班,怎么了?
科比:……没事,随便问问~~~


UDP广播:

发送方设置SO_BROADCAST选项,并将发送地址设置为广播地址即可。

int flag = 1;
setsockopt(s,SOL_SOCKET,SO_BROADCAST,&flag,sizeof(flag));

广播地址:
子网广播:{子网ID, 255} 例如:192.168.9.255
受限广播(路由器不转发): 255.255.255.255

接收方无需额外设置,显示的源地址为发送方的单播地址。


多播/组播:

只设置接收方加入多播组,发送方发送时指定目标地址为多播组地址即可。
可以同时加入多个多播分组。
组播地址取值范围:224.0.0.0~239.255.255.255

/*
 *  基于多播的UDP接收程序
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//-------------------------------------------------------------------- 
#define MCAST "224.0.0.88"   // 多播组号
#define PORT   12345         // 本机端口号
//-------------------------------------------------------------------- 
/*
 * 加入多播组
 */
int mutilcast_join(int s, struct ip_mreq* mreq)
{
  int ret;
    
  // 设置多播的TTL值,如果转发的次数等于指定值,则不再转发
  int ttl = 10;
  ret = setsockopt(s,IPPROTO_IP,IP_MULTICAST_TTL,&ttl,sizeof(ttl));
  if(ret < 0){
    perror("IP_MULTICAST_TTL");
    return -1;
  }
  // 设置数据是否发送到本地回环接口: 不发送
  int loop = 0;
  ret = setsockopt(s,IPPROTO_IP,IP_MULTICAST_LOOP,&loop,sizeof(loop));
  if(ret < 0){
    perror("IP_MULTICAST_LOOP");
    return -2;
  }
  
  // 加入多播组
  ret = setsockopt(s,IPPROTO_IP,IP_ADD_MEMBERSHIP,mreq,sizeof(struct ip_mreq));
  if(ret < 0){
    perror("IP_ADD_MEMBERSHIP");
    return -3;
  }     
  return 0;
}
//-------------------------------------------------------------------- 
/*
 * 离开多播组
 */
int mutilcast_leave(int s, struct ip_mreq* mreq)
{
    int ret;    
  ret = setsockopt(s,IPPROTO_IP,IP_DROP_MEMBERSHIP,&mreq,sizeof(mreq));
  if(ret < 0){
    perror("IP_DROP_MEMBERSHIP");
  }   
  return ret;   
}
//-------------------------------------------------------------------- 
/*
 * 主程序入口
 */
int main(int argc,char*argv[])
{
  int s; 
  int ret;
  int size;
  char rxbuf[1024];            // 接收数据缓冲区
  char ipbuf[20];              // IP地址转字符串      
  struct sockaddr_in localaddr;    // 本机地址
  struct sockaddr_in fromaddr;     // 远端地址
  struct ip_mreq mreq;         // 多播参数
  
  // 建立udp套接字
  s = socket(AF_INET,SOCK_DGRAM,0);
  if(s < 0){
   perror("socket error");
    return -1;
  }
  
  // 绑定本机端口
  localaddr.sin_family = AF_INET;
  localaddr.sin_port   = htons(PORT);
  localaddr.sin_addr.s_addr = htonl(INADDR_ANY);  
  //绑定地址结构到套接字
  ret = bind(s,(struct sockaddr*)&localaddr,sizeof(localaddr));
  if(ret < 0){
    perror("bind error");
    return -1;
  }
              
  //加入多播组  
  mreq.imr_multiaddr.s_addr = inet_addr(MCAST);   //多播组的IP
  mreq.imr_interface.s_addr = htonl(INADDR_ANY);  //本机的默认接口IP
  mutilcast_join(s, &mreq);
    
  //循环接收多播组的消息
  while(1)
  {
    int len = sizeof(fromaddr);
    memset(rxbuf,0,sizeof(rxbuf));
    size = recvfrom(s,rxbuf,1024,0,(struct sockaddr*)&fromaddr,&len);
    if(size < 0){
      perror("recvfrom ");
      return -1;
    }
    
    // 显示收到的信息   
    printf("receive message from:%s:%d\r\n",
           inet_ntop(AF_INET, &fromaddr.sin_addr, ipbuf, sizeof(ipbuf)),
           ntohs(fromaddr.sin_port));
    printf("%s",rxbuf);
    
    // 向发送端发送回应
    size = sendto(s,"OK",2,0,(struct sockaddr*)&fromaddr,sizeof(fromaddr));
  }
  
  mutilcast_leave(s, &mreq);  // 离开多播组
  close(s);                   // 关闭套接字
  return 0;
}

应用场景:

  1. 对于无屏显示的设备,可以过多播模式,来接收客户机的命令,返回自己的IP地址。
  2. 可以将日志通过多播发送出来,监听端加入多播组即可接收日志。

- 阅读全文 -

Linux应用笔记--vi


问:有什么简单的方法可以产生一组随机字符串?
答:让新手退出vi.


基本命令:

保存退出
:wq

不保存退出
:q!

保存不退出
:w

跳到第100行
:100

查找指定字符串:
:/str1
查找下一个:
n
查找上一个:
shift + n

复制当前行:
yy
粘贴复制行:
p

从本行向下复制3行:
y ↓ 2
从本行向上复制3行:
y ↑ 2

撤销最近一次操作:
u
撤销本行操作:
shift + u

sed编辑:

:[address]s/pattern/replacement/flag
flag: g表示该行全部匹配项,无此选项,仅替换第1个匹配项

将第3行中所有的str1替换成str2

:3 s/str1/str2/g

将全文中所有的str1替换成str2

%s/LED/KEYS/g
或者:
:g/str1/s//str2/g
第1个g表示所有行,第2个g表示每行所有匹配

删除空白行: 删除只有空格或制表符内容的行

:g/^[\ '\t']*$/d

删除空行: 什么内容都没有

:g/^$/d

配置文件:
全局配置文件: /etc/vim/vim.tiny
用户配置文件: ~/.vimrc
建议只修改用户配置文件,以防止影响其他用户使用。

自动匹配编码:

" 双引号表示行注释
set encoding=utf-8 
set fileencodings=ucs-bom,utf-8,cp936

cp936简体中文(gb2312)

vi在编辑模式移动光标时,会产生ABCD?

" 设置非兼容模式(兼容什么?)        
set nocompatible

显示/取消行号

set number
set nonumber

文件格式转换: 主要是换行符不同

转换为UNIX格式:

:set fileformat=unix

转换为DOS格式:

:set fileformat=dos

文件编码转换:
查看当前编码:

:set fileencoding

转换为utf-8

:set fileencoding=utf-8

转换为cp936(gb2312)

:set fileencoding=cp936


合并第3行和第4行:

:3j

合并第3行至第8行:

:3,8 j

或者在normal模式下移第3行:
5J

- 阅读全文 -

LwIP应用笔记--UDP应用


UDP通信

首选创建一个PCB块

struct udp_pcb* upcb;
upcb = udp_new();
// 绑定本地端口
udp_bind(upcb, IP_ADDR_ANY, 1234); 
// 连接远程端口(可省略)
udp_connect(upcb, &remote, 5555);

UDP发送:

struct pbuf *p; 
// 在POOL中分配pbuf空间(无操作系统时一般用POOL)
p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_POOL);    
if(p)
{    
    // 复制需要发送的数据到pbuf */
    pbuf_take(p, buff, len);

    // 发送数据至绑定的地址和端口    
    upd_send(upcb, p);    
    // 发送数据到指定地址和端口    
    udp_sendto(upcb, p, ipaddr, port);        
    // 指定网卡发送数据     
    udp_sendto_if(upcb, p, ipaddr, port, netif); 
}

// 释放pbuf空间(重要)
pbuf_free(p);   

UDP接收:

// 首先声明接收回调函数
void udp_recv_callback(void* arg,      // udp_recv的第3个参数
                struct udp_pcb* upcb,  // 本机描述符
                struct pbuf *p,        // 接收数据
                struct ip_addr *addr,  // 发送端IP
                uint16_t port)         // 发送端口
{
  // 将接收到的数据原路返回
  udp_sendto(upcb, p, &ipaddr, port);

  // 重要:回调函数的数据是动态申请的,一定要释放
  pbuf_free(p); 
}

// UPD接收到数据时,会调用回调函数处理,如果需要传入参数,
// 则通过第3个参数传入指针
udp_recv(upcb, udp_recv_callback, NULL);
    

重新设置IP:

// 修改网络参数前,先禁用网卡    
netif_set_down(netif);  

netif_set_ipaddr(netif,  &ipaddr);  // 设置IP地址
netif_set_netmask(netif, &netmask); // 设置子网掩码
netif_set_gw(netif, &gateway);      // 设置网关
 
// 设置全部参数(与上边的操作选一种)
// netif_set_addr(netif, &ipaddr, &netmask, &gateway);

// 修改完成后,重新启动网卡     
netif_set_up(netif);    

组播

发送组播: 发送不需要特殊设置,只需要向目地地址设置为组播地址即可。
组播地址取值范围:224.0.0.0~239.255.255.255

接收组播:

修改协议栈使能组播功能

// lwipopts.h
// 使能IGMP功能
#define LWIP_IGMP    1

// opt.h
// 添加随机接口
#include <stdlib.h>
#define LWIP_RAND() rand()

注意事项:
需要使能网卡驱动中的组播功能。

示例代码:

ip_addr_t group;
IP4_ADDR(&group, 224,1,1,2);    // 组播号(D类IP地址)  

// 加入组播分组
igmp_joingroup(IP_ADDR_ANY,(struct ip_addr *)(&group));   
// igmp_joingroup(&local_ip,(struct ip_addr *)(&group));

// 脱离组播分组    
igmp_leavegroup(IP_ADDR_ANY, &group);   

- 阅读全文 -

Linux应用程序--CAN总线


文章摘要:本文描述了关于CAN总线应用程序的编程。
内核版本:linux-3.8.13
硬件平台:AM335x


内核配置: 添加CAN驱动程序及协议

[*] Networking support --->
    <*> CAN bus subsystem support  --->
        <*> Raw CAN Protocol (raw access with CAN-ID filtering)
        <*> Broadcast Manager CAN Protocol (with content filtering)
            CAN Device Drivers  --->
                <*> Bosch D_CAN devices  --->
                    <*>   Generic Platform Bus based D_CAN driver

AM335x CAN控制器驱动程序位于:drivers/net/can/c_can目录下
c_can_platform.c
c_can.c


系统设置:命令及说明:

配置CAN总线参数

# ip link set can0 type can bitrate 500000 triple-sampling on

或者

# canconfig can0 bitrate 500000 ctrlmode triple-sampling on

bitrate参数用于设置波特率,此处设置为500K bps.

使能CAN总线接口

# ip link set can0 up

或者

# canconfig can0 start 

此命令完成后,可通过ifconfig查看到相关接口。

关闭CAN总线接口

# ip link set can0 down

或者

# canconfig can0 stop

示例代码:

/*
 * 初始化CAN控制器
 */
int can_open(char* name)
{
    int fd;
    struct ifreq can_ifr;
    struct sockaddr_can can_addr; 
    // int flag = 1; 
       
    // 初始化socket套接字用于CAN设备
    fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);     
            
    strcpy(can_ifr.ifr_name, name);     
    ioctl(fd, SIOCGIFINDEX, &can_ifr);        // 指定can设备   
      
    can_addr.can_family  = AF_CAN;            // 指定协议族
    can_addr.can_ifindex = can_ifr.ifr_ifindex;  
             
    bind(fd, (struct sockaddr *)&can_addr, sizeof(can_addr)); // 绑定
    //ioctl(fd, FIONBIO, &flag);        //设置为非阻塞模式  
    return fd;  
}
/*
 *  向CAN总线发送数据
 */
int can_send(int can, int id, unsigned char* buff)
{
    int ret; 
    struct can_frame can_frm = {0};
    
    can_frm.can_id  = id;      
    can_frm.can_dlc = 8;  
    memcpy(can_frm.data, buff, 8);
    
    ret = write(can, &can_frm, sizeof(can_frm));    
    if(ret != sizeof(can_frm)) 
    {   
        printf("can send error: id = %X\r\n", id);  
    }

    return 0;
}
/*
 *  向CAN总线读取数据
 */
int can_recv(int can, struct can_frame* pcf)
{
    int rxlen;
    
    // 正常情况下返回值为16(struct can_frame的长度)
    rxlen = read(can, pcf, sizeof(struct can_frame));
    if(rxlen != sizeof(struct can_frame))    
    {           
        return -1;    // 读取失败
    }

    return 0;
}

- 阅读全文 -


Copyright©2025 春天花会开, All Rights Reserved. Email: webmaster@oroct.com