首先创建vim main.c初始化设备文件
#include <stdio.h>
int g_buttonfd ;
int g_ledfd;
int g_mixerfd;int main()
{InitDriver();return 0;
}
按键设备文件,用于操作硬件设备
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_Hint 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_Hint 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_Hstruct 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;}}}
}