二、音箱初始化

文章描述了一个嵌入式系统中使用C语言进行设备初始化,包括按键、LED和混音器设备,并通过`select`函数实现对设备文件和网络套接字的IO复用。程序还包括了网络初始化、连接服务器、LED状态控制以及通过链表存储音乐文件名的功能。
摘要由CSDN通过智能技术生成

首先创建vim main.c初始化设备文件

#include <stdio.h>
int g_buttonfd ;
int g_ledfd;
int g_mixerfd;

int main()
{
    InitDriver();
    return 0;
}


  1. 按键设备文件,用于操作硬件设备

vim deviece.c

//用于操作硬件设备
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#

extern int g_buttonfd;
extern int g_ledfd;
extern int g_mixerfd;


int InitDriver()
{
    //打开按键设备文件
    g_buttonfd = open("/dev/buttons", O_RDONLY);
    if (-1 == g_buttonfd)
    {
        return FAILURE;
    }

    //打开led设备文件
    g_ledfd = open("/dev/leds", O_WRONLY);
    if (-1 == g_ledfd)
    {
        return FAILURE;
    }


    //打开minxer设备文件
    g_mixerfd = open("/dev/mixer", O_WRONLY);
    if (-1 == g_mixerfd)
    {
        return FAILURE;
    }


    return SUCCESS;
}

新建vim main.h

#ifndef MAIN_H
#define MAIN_H

#define SUCCESS     10000
#define FAILURE     10001

#endif

声明设备头文件vim devide.h

#ifndef DEVICE_H
#define DEVICE_H

int InitDriver();


#endif

对主函数做返回值判断main.c

#include <stdio.h>
int g_buttonfd ;
int g_ledfd;
int g_mixerfd;

int main()
{
    int ret;
    ret = InitDriver();     //打开设备文件
    if (FAILURE == ret)
    {
        printf("初始化设备文件失败\n");
        exit(1);
    }
    
    return 0;
}

设备初始化完后对网络进行初始化

#include <stdio.h>
int g_buttonfd ;
int g_ledfd;
int g_mixerfd;

int main()
{
    int ret;
    ret = InitDriver();     //打开设备文件
    if (FAILURE == ret)
    {
        printf("初始化设备文件失败\n");
        exit(1);
    }
    ret = InitSocket();      //初始化网络
    if (FAILURE == ret)
    {
        printf("初始化网络失败\n");
        //初始化失败,点亮 2 个LED灯
        led_on(0);
        led_on(1);
    }

    
    return 0;
}

下面实现网络初始化代码:

vim socket.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "main.h"
int InitSocket()
{
    g_sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if (-1 == g_sockfd)
    {
        return FAILURE;
    }
}

socket头文件socket.h

#ifndef SOCKET_H
#define SOCKET_H

#define SERVER_PORT   8000
#define SERVER_IP     "47.101.128.140"


int InitSocket();
#endif

当socket创建好后,启动线程发起服务器连接

socket.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "main.h"

extern int g_sokcetfd;

int InitSocket()
{
    g_sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if (-1 == g_sockfd)
    {
        return FAILURE;
    }
    pthread_t tid;
    int ret = pthread_create(&tid, NULL, connect_cb, NULL);
    if (ret != 0)
    {
        return FAILURE;
    }


}

创建线程后启动一个线程函数connect_cb

void *connect_cb(void *arg)
{
    int count = 5, ret;
    struct sockaddr_in server_addr;

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = PF_INET;
    server_addr.sin_port = htons(SERVER_PORT);
    server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);

    while (count--)
    {
        ret = connect(g_sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
        if (ret == -1)
        {
            sleep(5);
            continue;
        }
        
        //连接成功,点亮 4 个LED灯
        led_on(0);
        led_on(1);
        led_on(2);
        led_on(3);



        break;
    }

    return NULL;
}

考虑到会连接失败,线程会向服务器发起5次连接,如果五次均为成功,返回失败。

因为开发板有led,现在考虑连接的时候用led提示,发起连接的时候第一个灯亮,初始化时led灭,

连接成功4个灯都亮

device.c

    //所有LED灭
    int i;
    for (i = 0; i < 4; i++)
    {
        ioctl(g_ledfd, 0, i);
    }

void led_on(int which)
{
    ioctl(g_ledfd, 1, which);    
}

void led_off(int which)
{
    ioctl(g_ledfd, 0, which);
}

device.h

#ifndef DEVICE_H
#define DEVICE_H

int InitDriver();
int led_on(int which);
int led_off(int which);

#endif

在socket.c加入device.h头文件

#include <sys/socket.h>
#include "main.h"
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include "device.h"

在main.c中做一个判断,当网络初始化失败后亮两个灯


    ret = InitSocket();      //初始化网络
    if (FAILURE == ret)
    {
        printf("初始化网络失败\n");
        //初始化失败,点亮 2 个LED灯
        led_on(0);
        led_on(1);
    }

初始化网络,一旦连接成功后,下面就要监听,到底是按键还是网络有信息发过来

音箱的触发要么是按键触发g_buttonfd,要么是app触发g_sockfd

下面写一个函数采用select复用io来监听fd

在main.c中

m_select();

新建一个vim selec.c

#include <stdio.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

extern int g_buttonfd;
extern int g_sockfd;

void show()
{
    printf("1、开始播放\n");
    printf("2、结束播放\n");
    printf("3、暂停播放\n");
    printf("4、继续播放\n");
    printf("5、上一首\n");
    printf("6、下一首\n");
    printf("7、增加音量\n");
    printf("8、减小音量\n");
    printf("9、顺序播放\n");
    printf("a、随即播放\n");
    printf("b、单曲循环\n");
}

void m_select()
{
   
    show();
    fd_set readfd, tmpfd;
    int ret;
    int maxfd = (g_buttonfd > g_sockfd) ? g_buttonfd : g_sockfd;

    FD_ZERO(&readfd);
    FD_ZERO(&tmpfd);

    FD_SET(g_buttonfd, &readfd);
    FD_SET(g_sockfd, &readfd);
    FD_SET(0, &readfd);//标准输入添加到集合,调试用

    while (1)
    {
        tmpfd = readfd;
        ret = select(g_maxfd + 1, &tmpfd, NULL, NULL, NULL);
        if (-1 == ret && errno != EINTR)
        {
            perror("select");
        }
        else if (-1 == ret && errno == EINTR)
        {
            continue;
        }

        if (FD_ISSET(g_sockfd, &tmpfd))           //TCP有数据可读
        {

        }
        else if (FD_ISSET(g_buttonfd, &tmpfd))    //按键有数据可读
        {
         
        }
    }
}

再开始播放音乐的时候,需要把所有音乐的名字读出来。

main.c

    //读取音乐
    GetMusic();

音乐的名字用链表来存储,需要初始化链表

vim main.c中

#include "main.h"
#include "device.h"
#include <stdlib.h>

int g_buttonfd ;
int g_ledfd;
int g_mixerfd;
int g_sockfd ;
struct Node *head;

int main()
{
        //初始化链表
    ret = InitLink();
    if (FAILURE == ret)
    {
        printf("链表初始化失败\n");
        exit(1);
    }
}

新建一个链表link.h头文件

#ifndef LINK_H
#define LINK_H

struct Node
{
    char music_name[64];
    struct Node *next;
    
};
typedef struct Node Node;

int InitLink();


#endif

初始化链表link.c

#include <stdio.h>
#include <stdlib.h>
#include "main.h"
#include <string.h>
#include "link.h"
extern struct Node *head;

//初始化链表
int InitLink()
{
    head = (Node *)malloc(sizeof(Node) * 1);
    if (NULL == head)
    {
        return FAILURE;
    }

    head->next = NULL;

    return SUCCESS;
}

下面要读取音乐vim player.h

#ifndef PLAYER_H
#define PLAYER_H

#include <unistd.h>

#define MUSICPATH   "/root/music_list/"
//测试中音乐所在文件目录
#endif

下面需要从目录中获取音乐的名字放在链表中,打开目录用opendir

vim player.c

#include <stdio.h>
#include "link.h"
#include "main.h"
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
#include "player.h"

extern Node *head;

void GetMusic()
{
    //打开目录
    DIR *dir = opendir(MUSICPATH);
    if (NULL == dir)
    {
        perror("opendir");
        exit(1);
    }

    struct dirent *file = NULL;

    //读取目录
    while ((file = readdir(dir)) != NULL)
    {
        if (file->d_type != 8)      //不是普通文件
        {
            continue;
        }

        if (!m_mp3_end(file->d_name))   //不是mp3文件
        {
            continue;
        }

        printf("%s\n", file->d_name);    //如果是.mp3结尾,输出读取到的文件名字

        int ret = InsertLink(head, file->d_name); //把音乐名字插入到链表
        if (FAILURE == ret)
        {
            printf("歌曲插入失败\n");
            exit(1);
        }
    }
}

判断歌曲是不是.mp3结尾是返回1不是返回0,m_mp3_end

//判断是不是.mp3结尾
int m_mp3_end(const char *name)
{
    const char *ptr = name; //传进来的文件名字

    while (*ptr != '\0')    //循环到文件名字末尾
    {
        ptr++;
    }
    int i;
    for (i = 0; i < 4; i++)  //因为现在ptr在\0位置,所以需要往前走四个位置定位到。MP3,运行结束在.位置
    {
        ptr--;
    }
    
    if (ptr < name)
        return 0;
    
    return (strcmp(ptr, ".mp3") == 0) ? 1 : 0; //判断是不是.mp3
}

vim link.c

int InsertLink(Node *h, const char *name)
{
    if (NULL == h || NULL == name) //链表初始化失败为空或者传入文件名有问题为空
    {
        return FAILURE;
    }

    Node *p = h; //新建节点指向头结点

    while(p->next)
    {
        p=p->next;  // 定位到链表最后一个位置
    }
    Node *n = (Node *)malloc(sizeof(Node) * 1);
    if (NULL == n)
    {
        return FAILURE;
    }

    n->next = h;
    strcpy(n->music_name, name); //将音乐的名字写道新建的节点中
    p->next = n;


    return SUCCESS;
}

在select.c中加一个标准输入 的测试代码,后续会删除,主要用于测试功能

#include <stdio.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

extern int g_buttonfd;
extern int g_sockfd;

void show()
{
    printf("1、开始播放\n");
    printf("2、结束播放\n");
    printf("3、暂停播放\n");
    printf("4、继续播放\n");
    printf("5、上一首\n");
    printf("6、下一首\n");
    printf("7、增加音量\n");
    printf("8、减小音量\n");
    printf("9、顺序播放\n");
    printf("a、随即播放\n");
    printf("b、单曲循环\n");
}

void m_select()
{
   
    show();
    fd_set readfd, tmpfd;
    int ret;
    int maxfd = (g_buttonfd > g_sockfd) ? g_buttonfd : g_sockfd;

    FD_ZERO(&readfd);
    FD_ZERO(&tmpfd);

    FD_SET(g_buttonfd, &readfd);
    FD_SET(g_sockfd, &readfd);
    FD_SET(0, &readfd);//标准输入添加到集合,调试用

    while (1)
    {
        tmpfd = readfd;
        ret = select(g_maxfd + 1, &tmpfd, NULL, NULL, NULL);
        if (-1 == ret && errno != EINTR)
        {
            perror("select");
        }
        else if (-1 == ret && errno == EINTR)
        {
            continue;
        }

        if (FD_ISSET(g_sockfd, &tmpfd))           //TCP有数据可读
        {

        }
        else if (FD_ISSET(g_buttonfd, &tmpfd))    //按键有数据可读
        {
         
        }
        else if(FD_ISSET(0, &tmpfd)
        {
            int func;
            scanf(“%d”,&func);
            switch(func)
            {
                case 1:
                    break;
                case2:
                    break;
               }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值