Linux+ARM 简单环境检测---软件部分

news2024/11/27 14:42:43

1、前言

        这个是我学习linux+ARM的在做的第一个软硬件结合项目,以往的类似这种整体类项目还是光单片机的时候,linux软件部分学习了差不多快一年了,因为各种事情耽搁,这个项目一直没有静下心来完成,不过终于哈哈哈哈搞完了软件部分。其实并行的还想做另一个涉及到can通信的项目,那个重点可能是偏各种通信,不过软件部分大同小异,直接改改就可以变成那个的软件部分。驱动部分等我搞定我再发出来。(板子为什么选友善之臂S2440,因为便宜。。不过最近有点小钱又买了一块正点原子的6ULL,还在路上)

2、摘要

  1. 本文主要记录并分享软件部分,用于模拟将数据上传到互联网上以供使用,内容包含数据上传、数据库存储、屏幕显示三部分
  2. 使用软件:VMware+Ubuntu22.04
  3. ARM版芯片:S3C2440(友善之臂mini2440)
  4. 上传采用MQTT协议上传到OneNet云,数据库使用sqlite3,屏幕显示采用FrameBuffer 帧缓存技术
  5. 实现效果:数据可以在云上、屏幕上、数据库中查看
  6. 学习文章会在本文中标记出来

3、内容简介

软件部分内容一共分为三部分:

  1. 数据上传部分:将获得的数据上传到OneNet云上

  2. 数据库存储部分:将数据存储到数据库中

  3. 屏幕显示部分:Framebuff显示在屏幕上

4、应用到的知识

完成上面所有的功能使用到的相关知识,我按照我自己的学习顺序梳理了一下

  1. 文件编程:系统函数(文件I/O) open read write close 等等

  2. 进程:进程原理及使用、进程之间的通信等等

  3. 线程:线程原理及使用,线程之间的通信等等

  4. 网络TCP通信:socket套接字、原理及使用等等,bind、listen、accept,读写函数recv、send等

  5. MQTT协议:linux上代码实现以及软件使用,使用MQTT协议上传到OneNet云上(HTTP协议理论上也可以,但是MQTT网上教程多)

  6. 数据库sqlite:数据库的基本操作(增删改查),相关函数 sqlite3_open等等

  7. FrameBuffer帧缓存:理解及代码实现流程

  8. 数据结构:链表,C语言代码实现(与线程邮箱有关)

  9. 线程邮箱:涉及到数据结构链表,线程邮箱是后面实现上面功能三部分整合的时候才知道的这个名词,挺重要的,用起来比线程之间sem信号量好用。

5、软件框架

6、代码

6.1 数据上传部分

数据上传部分可以分为两部分:OneNet云网站相关配置和MQTT相关代码编写,第一部分按照网上资料逐一配置即可,第二部分比较复杂的点是需要安装MQTT的库,代码流程固定:连接发送断开

6.1.1 流程图

6.1.2 实现代码

 没有代码注释,因为代码很多,需要自己去理解一下

//head.h
#ifndef _HEAD_H_
#define _HEAD_H_

#include <MQTTAsync.h>
#include <MQTTClient.h>

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>

#define NEW_IP "tcp://183.230.40.96:1883"
#define NAME "cityheathly"
#define PRODUCT_ID "gUsHWQWmcp"
#define PASSWD "version=2018-10-31&res=products%2FgUsHWQWmcp%2Fdevices%2Fcityheathly&et=1837255523&method=md5&sign=sAR1RwRYplyky9oRoTAuHA%3D%3D"
#define QOS 0
#define TIMEOUT 10000L

#define CONNECT_OK 1
#define CONNECT_FAIL 2

static char topic[2][200] = {0};
static int id = 1000;
static MQTTClient client;
volatile static MQTTClient_deliveryToken deliveredtoken;

extern int mqtt_connect_flag;
void mqtt_deinit();
void mqtt_send(char * db ,float db_value,char *dust,float dust_value,char *pos,char *pos_value);
void mqtt_init();
#endif
//mqqt.c
#include "head.h"

void pack_topic(char * dev_name, char * pro_id)
{
        sprintf(topic[0], "$sys/%s/%s/thing/property/post/reply", pro_id, dev_name);        //订阅
        sprintf(topic[1], "$sys/%s/%s/thing/property/post", pro_id, dev_name);                        //发布
}
int MessageArrived (void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
    
    printf("MessageArrived \n");
    printf("    topic:%s\n",topicName);
    printf("  message : ");

    char *payloadptr = (char *)message->payload;
    int i ;
    for(i =0 ; i < message->payloadlen ; i++)
    {
        putchar(*payloadptr++);
    }
    putchar('\n');
    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
    return 1;
}
//传递完成
void DeliveryComplete(void *context, MQTTClient_deliveryToken dt)
{
        printf("Message with token value %d delivery confirmed\n", dt);
        deliveredtoken = dt;
}
//连接丢失
void ConnectLost(void *context, char *cause)
{
    printf("\n Connect lost\n");
    printf("cause :%s\n",cause);
}
int mqtt_connect_flag=0;
void mqtt_init()
{
    pack_topic(NAME,PRODUCT_ID);
    int creat_flag = 0;
    int setcallback_flag = 0;
    int connect_flag = 0;
    creat_flag = MQTTClient_create(&client,NEW_IP,NAME,MQTTCLIENT_PERSISTENCE_NONE,NULL);
    if(creat_flag != MQTTCLIENT_SUCCESS)
    {
        printf("creat fail:%d\n",creat_flag);
        exit(1);
    }

    setcallback_flag = MQTTClient_setCallbacks(client,NULL,ConnectLost,MessageArrived,DeliveryComplete);
    if(setcallback_flag != MQTTCLIENT_SUCCESS)
    {
        printf("faile setcallback :%d\n",setcallback_flag);
    }
    
    MQTTClient_connectOptions connect_opt = MQTTClient_connectOptions_initializer;
    connect_opt.keepAliveInterval = 20;
    connect_opt.cleansession = 1;
    connect_opt.username = PRODUCT_ID;
    connect_opt.password = PASSWD;
    connect_flag =  MQTTClient_connect(client,&connect_opt);
    if(connect_flag != MQTTCLIENT_SUCCESS)
    {
        printf("connect fail : %d\n",connect_flag);
        mqtt_connect_flag = CONNECT_FAIL;
    }
    else
    {
        mqtt_connect_flag = CONNECT_OK;
    }
}
void mqtt_send(char * db ,float db_value,char *dust,float dust_value,char *pos,char *pos_value)
{
    int send_flag = 0;
    MQTTClient_deliveryToken deliveryToken;
    MQTTClient_message test2_pubmsg = MQTTClient_message_initializer;
    // 需要发送的正文
    char message[1024]={0};
    test2_pubmsg.qos = QOS;
    test2_pubmsg.retained = 0;
    test2_pubmsg.payload =message;
    sprintf(message,"{\"id\":\"%d\",\"version\":\"1.0\",\"params\":{\"%s\":{\"value\":%f},\"%s\":{\"value\":%f},\"%s\":{\"value\":\"%s\"}}}",id++, db,db_value,dust,dust_value, pos,pos_value);
    test2_pubmsg.payloadlen = strlen(message);
    
    printf("%s\n",message);
    send_flag = MQTTClient_publishMessage(client,topic[1],&test2_pubmsg,&deliveryToken) ;
    if(send_flag != MQTTCLIENT_SUCCESS)
    {
        printf("client to publish fail : %d\n",send_flag);
        exit(1);
    }
        printf("Waiting for up to %d seconds for publication on topic %s for client with ClientID: %s\n"
                        ,(int)(TIMEOUT/1000), topic[0], NAME);
    MQTTClient_waitForCompletion(client,deliveryToken,TIMEOUT);
    sleep(1);
}
void mqtt_deinit()
{
    MQTTClient_disconnect(client, 10000);
    MQTTClient_destroy(&client);
}

6.2 数据存储部分

数据存储部分就一个点:使用sqlite3进行数据库的创建,新增,删除,调用sqlite3的库中代码实现,流程过于简单就不画流程图了

//sql.h
#ifndef _SQL_H_
#define _SQL_H_
#include <sqlite3.h>
void sqlite_control(sqlite3 *db,float noise,float flower,char *pos1);

#endif
//sql.c
#include "sql.h"
#include <stdio.h>
#include <sqlite3.h>
#include <string.h>
#include <unistd.h>
char message[100]={0};
int callback(void *arg,int n,char **pvalue,char **pname)
{
    static int flag = 0;
    int i =0;
    if(flag ==0)
    {
        for (i =0;i<n;i++)
        {
            printf("%s\t",pname[i]);
        }
        putchar('\n');
        for (i =0;i<n;i++)
        {
            printf("------ ");
        }
        putchar('\n');
        flag = 1;
    }
    for (i =0;i < n;i++)
    {
        sprintf(message,"%s %s",message,pvalue[i]);
        printf("%s\t",pvalue[i]);
    }
    printf("\n--------------------------\n");
    printf("\n %s \n",message);
    return 0;
}

void sqlite_control(sqlite3 *db,float noise,float flower,char *pos1)
{
    if(sqlite3_open("data.db",&db) !=0 )
    {
        printf("sqlite3_open fail! :%s \n",sqlite3_errmsg(db));
    }
    char buf[500];
    char sql[1024] = {0};
    char *errmsg = NULL;
    sqlite3_exec(db,"create table dict (id INTEGER PRIMARY KEY ASC,noise float, flower float, pos1 text,dt datetime)",NULL,NULL,&errmsg);
    int i =0;
#if 1
    sprintf(sql,"insert into dict values(NULL,%f,%f,\"%s\",datetime('now','+8 hours'));",noise,flower,pos1);
    if(sqlite3_exec(db,sql,callback,NULL,&errmsg)!=0)
    {
        printf("sqlite3_exec fail :%s\n",errmsg);
    }
    printf("%s\n",message);
    fflush(stdout);
    sleep(1);
#endif
#if 0
    for(int i =0 ;i<10 ;i++)
    {
        sprintf(sql,"select * from dict where id =%d",i);
        if(sqlite3_exec(db,sql,callback,NULL,&errmsg)!=0)
        {
            printf("sqlite3_exec fail :%s\n",errmsg);
        }
        //上传云端数据
        //清空上传数据
        memset(message,0,sizeof(message));
        //删除信息
        sprintf(sql,"delete from dict where id=%d",i);
        if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=0)
        {
            printf("sqlite3_exec fail :%s\n",errmsg);
        }
        printf("data delect succes!\n");
    }
#endif
    sqlite3_close(db);
}

6.3 显示部分

购买的屏幕是配套的,使用的技术是Framebuff,相对上面的比较特殊,因为要开启板子上的功能设备,不过流程也是同样的固定顺序:打开,读取,显示,关闭

#ifndef __FRAMEBUFF_H__
#define __FRAMEBUFF_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/fb.h>

/* 测试FrameBuff设备是否为RGB565标准 */
#define IS_RGB565_FORMAT(bits)                                (((bits) / 8 == 2) ? 1 : 0)
/* 测试FrameBuff设备是否为RGB888标准 */
#define IS_RGB888_FORMAT(bits)                                (((bits) / 8 == 4) ? 1 : 0)

/* 填充RGB888颜色 */
#define FILL_RGB888_COL(col, r, g, b)                do { \
        (col)->R = r; \
        (col)->G = g; \
        (col)->B = b; \
} while (0)

/* 填充RGB565颜色 */
#define FILL_RGB565_COL(col, r, g, b)                do { \
        (*(short *)col) = ((((r >> 3) << 11) & 0xF800) | (((g >> 2) << 5) & 0x07E0) | ((b >> 3) & 0x001F)); \
} while (0)

/* RGB888 像素点结构类型 */
typedef struct rgb888 
{
        unsigned char B;                                                //红
        unsigned char G;                                                //绿
        unsigned char R;                                                //蓝
        unsigned char Reserved;                                        //保留(内存对齐)
}RGB888_T;

/* RGB565 像素点结构类型 */
typedef struct rgb565
{
        unsigned short R:5;                                                //红
        unsigned short G:6;                                                //绿
        unsigned short B:5;                                                //蓝
}RGB565_T;

/* FrameBuff结构信息类型 */
typedef struct framebuff_dev
{
        RGB888_T *pRGB888Addr;                                        //RGB888显存首地址
        RGB565_T *pRGB565Addr;                                        //RGB565显存首地址
        struct fb_var_screeninfo ScreenInfo;        //Framebuff设备信息
}FB_T;

extern FB_T *FrameBuffInit(const char *pDevName);
extern int FrameBuffDeInit(FB_T *pFb);
extern int DrawOnePixel(FB_T *pFb, int x, int y, unsigned char TmpR, unsigned char TmpG, unsigned char TmpB);
#include "framebuff.h"
#include <sys/mman.h>

FB_T *FrameBuffInit(const char *pDevName)
{
        int fb = 0;
        int ret = 0;
        FB_T *pFbInfo = NULL;

        pFbInfo = malloc(sizeof(FB_T));
        if (NULL == pFbInfo)
        {
                perror("create fb info struct failed");
                return NULL;
        }

        fb = open(pDevName, O_RDWR);
        if (-1 == fb)
        {
                perror("fail to open");
                return NULL;
        }

        ret = ioctl(fb, FBIOGET_VSCREENINFO, &pFbInfo->ScreenInfo);
        if (-1 == ret)
        {
                perror("get screen info failed");
                return NULL;
        }

        printf("=================== Lcd Info ====================\n");
        printf("Width: %d\n", pFbInfo->ScreenInfo.xres_virtual);
        printf("Height: %d\n", pFbInfo->ScreenInfo.yres_virtual);
        if (IS_RGB565_FORMAT(pFbInfo->ScreenInfo.bits_per_pixel))
        {
                printf("FrameBuff Device Rgb565 Format!\n");
        }
        else if (IS_RGB888_FORMAT(pFbInfo->ScreenInfo.bits_per_pixel))
        {
                printf("FrameBuff Device Rgb888 Format!\n");
        }
        printf("================================================\n");

        if (IS_RGB565_FORMAT(pFbInfo->ScreenInfo.bits_per_pixel))
        {
                pFbInfo->pRGB565Addr = mmap(NULL, pFbInfo->ScreenInfo.xres_virtual * pFbInfo->ScreenInfo.yres_virtual * pFbInfo->ScreenInfo.bits_per_pixel / 8,
                                            PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0);
        }
        else if (IS_RGB888_FORMAT(pFbInfo->ScreenInfo.bits_per_pixel))
        {
                pFbInfo->pRGB888Addr = mmap(NULL, pFbInfo->ScreenInfo.xres_virtual * pFbInfo->ScreenInfo.yres_virtual * pFbInfo->ScreenInfo.bits_per_pixel / 8,
                                            PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0);
        }

        printf("create Frmamebuff size:%d display buff success!\n", pFbInfo->ScreenInfo.xres_virtual * pFbInfo->ScreenInfo.yres_virtual * pFbInfo->ScreenInfo.bits_per_pixel / 8);

        return pFbInfo;
}

int FrameBuffDeInit(FB_T *pFb)
{
        if (IS_RGB565_FORMAT(pFb->ScreenInfo.bits_per_pixel))
        {
                munmap(pFb->pRGB565Addr, pFb->ScreenInfo.xres_virtual * pFb->ScreenInfo.yres_virtual * pFb->ScreenInfo.bits_per_pixel / 8);
        }
        else if (IS_RGB888_FORMAT(pFb->ScreenInfo.bits_per_pixel))
        {
                munmap(pFb->pRGB888Addr, pFb->ScreenInfo.xres_virtual * pFb->ScreenInfo.yres_virtual * pFb->ScreenInfo.bits_per_pixel / 8);
        }

        free(pFb);

        return 0;
}

int DrawOnePixel(FB_T *pFb, int x, int y, unsigned char TmpR, unsigned char TmpG, unsigned char TmpB)
{
        RGB888_T *pTmp1 = NULL;
        RGB565_T *pTmp2 = NULL;

        if (IS_RGB888_FORMAT(pFb->ScreenInfo.bits_per_pixel))
        {
                pTmp1 = pFb->pRGB888Addr;
                pTmp1 += y * (pFb->ScreenInfo.xres_virtual) + x;
                FILL_RGB888_COL(pTmp1, TmpR, TmpG, TmpB);
        }
        else if (IS_RGB565_FORMAT(pFb->ScreenInfo.bits_per_pixel))
        {
                pTmp2 = pFb->pRGB565Addr;
                pTmp2 += y * (pFb->ScreenInfo.xres_virtual) + x;
                FILL_RGB565_COL(pTmp2, TmpR, TmpG, TmpB);
        }

        return 0;
}
int DrawString(FB_T *pFb, int x, int y,  const char *pstr, unsigned char TmpR, unsigned char TmpG, unsigned char TmpB)
{
        const char *ptmp = NULL;
        int i = 0;

        ptmp = pstr;
        while (*ptmp != '\0')
        {
                DrawOneAscii(pFb, x+10*i, y, *ptmp, TmpR, TmpG, TmpB);
                i++;
                ptmp++;
        }

        return 0;
}
void frame_control(FB_T *pFb,float db,float flower,char *pos1,char *pos2)
{
            char project_name[100]="Urban health data";

        char noise_data[100]={0};
        char flower_data[100] = {0};
 
        ClearScreen(pFb);
        
        sprintf(noise_data,"noise  %f",db);
        sprintf(flower_data,"flower %f",flower);

        DrawString(pFb,40,50,project_name,255,255,255);
        DrawString(pFb,50,100,pos1,255,255,255);
        DrawString(pFb,50,140,pos2,255,255,255);
        DrawString(pFb,50,250,flower_data,255,255,255);
        DrawString(pFb,50,200,noise_data,255,255,255);

        sleep(1);
}

6.4 整合

        整合这里,很让人头大,因为这三部分是都要独立执行的,因此肯定是需要使用线程,但是如果光使用线程和信号量,需要设置各种全局变量和标志,弄得很混乱。在搜索的过程中查到了线程邮箱,尝试着学习,原理弄清楚个大概,但是代码借鉴的其他博主大神,自己修改修改就可以用了。

        下面这个代码是做控制的整个.c文件,一共启用了三个线程,分别用于收集信息、发送云端,发送屏幕。收集信息由于还没开始弄硬件,所以调用了随机数模拟收集到的数据,数据是共享的,发送给其他两个线程。发送云端这里设计成:有网络数据上传到云服务器,无网络上传到数据库中。

#ifndef __LIST_H__
#define __LIST_H__
#include <pthread.h>
#include <stdlib.h>
#include <string.h>

typedef void*(*th_fun)(void* arg);
typedef struct{
    float noise;
    float flower;
    char *pos;
}DATATYPE;
typedef struct mail_data
{
    pthread_t   id_of_sender;
    char       name_of_sender[256];
    pthread_t   id_of_recver;
    char       name_of_recver[256];
    DATATYPE data;
}MAIL_DATA;
typedef struct queue{
    MAIL_DATA data;
    struct queue* next;
//        int pro;
}Que, *pQue;
typedef struct thread_node
{
    pthread_t tid;         //线程id号
    char name[256];        //线程名字 ,必须唯一
    Que *mail_head, *mail_tail;
    th_fun th;
}LIST_DATA;

typedef struct Link{
    LIST_DATA elem;
    struct Link *next;
}LIST_LINK;

typedef struct mail_box_system
{
    pthread_mutex_t mutex;  //保护邮件系统
    LIST_LINK *thread_list;
}MBS;
extern LIST_LINK * list_init();
extern LIST_LINK * list_for_each(LIST_LINK* head, char *name);

extern void list_add(LIST_LINK *head, LIST_LINK *info);

int  register_to_mail_system(MBS *mbs,char name[],th_fun th);
int destroy_mail_box_system(MBS*mbs);
MBS* create_mail_box_system();
extern MBS *mbs;

int wait_all_end(MBS*msb);
void* MQTT_th(void* arg);
void* data_collect_th(void* arg);
void* FramBuffer_th(void* arg);
#endif
#include "pthread_mail.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "list.h"
#include "queue.h"
#include "../head.h"
#include "../FrameBuff/framebuff.h"
#include "sql.h"
#define ENTER_CRITICAL_AREA(mutex)  do{pthread_mutex_lock(mutex);}while(0)
#define QUIT_CRITICAL_AREA(mutex)  do{pthread_mutex_unlock(mutex);}while(0)

unsigned pthread_index;

LIST_LINK *end_list = NULL;

MBS* mbs;

int send_msg(MBS*msb,char*recvname,DATATYPE data);
int recv_msg(MBS*msb,char*sendname,DATATYPE *data);

MBS* create_mail_box_system()
{
    MBS *temp =(MBS*)malloc(sizeof(MBS));

    if(NULL ==  temp)
    {
        perror("create_mail_box_system mutex malloc failure\n");
        return NULL;
    }
    int ret = pthread_mutex_init(&temp->mutex,NULL);
    if(0 != ret)
    {
        perror("create_mail_box_system mutex init failure\n");
        return NULL;
    }
    temp->thread_list = (LIST_LINK *)malloc(sizeof(LIST_LINK));
    temp->thread_list->next = NULL;
    printf("mail box create ok!! \n");
    return temp;
}

int destroy_mail_box_system(MBS*mbs)
{
    pthread_mutex_destroy(&mbs->mutex);
    LIST_LINK *temp = NULL;
    LIST_LINK *find = mbs->thread_list;
    while(find !=  NULL)
    {
        temp = find;
        find = find->next;
        free(temp);
    }
    free(find);
    return 0;
}

char *get_th_name(MBS*msb)
{
    pthread_t tid = pthread_self();
    LIST_LINK *find = msb->thread_list;
    LIST_LINK *end = end_list;
    while(find != end)
    {
        if(find->elem.tid == tid)
            break;
        find = find->next;
    }
    if(find->elem.tid == tid)
    {
        return find->elem.name;
    }
    else
        return NULL;
}
int  register_to_mail_system(MBS *mbs,char name[],th_fun th)
{
    LIST_LINK* temp =  (LIST_LINK *)malloc(sizeof(LIST_LINK));
    if(NULL == temp)
    {
        perror("register to mail malloc  \n");
        return -1;
    }
    strcpy(temp->elem.name ,name);
    temp->elem.th = th;
    temp->next = NULL;
    init_que(temp);

    pthread_t ret = pthread_create(&(temp->elem.tid),NULL,th,NULL);
    if(0!=ret)
    {
        perror("register to mail thread create\n");
        return -1;
    }

    list_add(mbs->thread_list, temp);
    printf("register mail system  |%s|  ok \n", temp->elem.name);

    return 0;
}

int unregister_from_mailbox(MBS*msb,char*name)
{
    LIST_LINK* find=msb->thread_list->next;
    LIST_LINK *temp = NULL;

    while(find !=  NULL)
    {
        temp = find;
        find = find->next;
        if(0 == strcmp(temp->elem.name ,name))
        {
            destroy(find);
            free(temp);
            return 0;
        }
    }

    if(0 == strcmp(find->elem.name ,name))
    {
        destroy(find);
        free(find);
        return 0;
    }
    return -1;
}

int wait_all_end(MBS*msb)
{
    LIST_LINK *find=msb->thread_list->next;
    LIST_LINK *end=end_list;
    while(find != end)
    {
        pthread_join(find->elem.tid,NULL);
        find = find->next;
    }
    pthread_join(find->elem.tid,NULL);
    return 0;
}

int send_msg(MBS*msb, char*recvname, DATATYPE data)
{
    MAIL_DATA* temp =  (MAIL_DATA *)malloc(sizeof(MAIL_DATA));

    temp->data = data;

    temp->id_of_sender = pthread_self();

    LIST_LINK *find = list_for_each(msb->thread_list, recvname);
    if (find == NULL)
    {
        printf("can,t find msg \n");
    }

    char* name = get_th_name(msb);
    strcpy(temp->name_of_sender,name);
    strcpy(temp->name_of_recver,recvname);
    ENTER_CRITICAL_AREA(&msb->mutex);
    in_queue(find, temp);
    QUIT_CRITICAL_AREA(&msb->mutex);
    return 0;
}

int recv_msg(MBS*msb,char*sendname,DATATYPE *data)
{
    MAIL_DATA* temp = (MAIL_DATA *) malloc(sizeof(MAIL_DATA));
    pthread_t tid =  pthread_self();

    LIST_LINK *find = msb->thread_list;

    while(find != NULL)
    {
        if( find->elem.tid == tid)
            break;
        find = find->next;
    }

    if( find->elem.tid == tid)
    {
        while (1)
        {
            if(find->elem.mail_head != find->elem.mail_tail)
            {
                ENTER_CRITICAL_AREA(&msb->mutex);
                out_queue(find, temp);
                QUIT_CRITICAL_AREA(&msb->mutex);
                break;
            }
        }
    }

    strcpy(sendname, temp->name_of_sender);
    *data = temp->data;
    free(temp);
    return 0;
}

void* data_collect_th(void* arg)
{
   DATATYPE info;
   
    while(1)
    {
        srand(time(NULL));
        // 生成在0到RAND_MAX之间的整数
        int random_int = rand();
        // 将整数映射到0到2000之间的浮点数
        info.noise = ((float)random_int / RAND_MAX) * 200;
        info.flower = ((float)random_int / RAND_MAX) * 100;
        send_msg(mbs,"mqtt",info);
        send_msg(mbs,"frambuffer",info);
        sleep(1);
    }
    return NULL;
}
void* MQTT_th(void* arg)
{
    sqlite3 *sqlite;
    while(1)
    {
        char sendname[256];
        DATATYPE data;
        recv_msg(mbs,sendname,&data);

        printf("mqtt_flag=%d\n",mqtt_connect_flag);
        if(mqtt_connect_flag == CONNECT_OK)
        {
            mqtt_send("db",data.noise,"dust",data.flower,"pos","199,N,200,S");
        }
        else if(mqtt_connect_flag == CONNECT_FAIL)
        {
            sqlite_control(sqlite,data.noise,data.flower,"1992,N,200,S");
        }
        else 
        {
            printf("mqtt_connect_flag has nothing!\n");
        }
    }
    mqtt_deinit();
    return NULL;
}
void* FramBuffer_th(void* arg)
{
        FB_T *pFb = NULL;
    pFb = FrameBuffInit("/dev/fb0");
    while(1)
    {
        DATATYPE data;
        char sendname[256];
        recv_msg(mbs,sendname,&data);
        
        char pos1[100]="12345.6789,N";
        char pos2[100]="98765.4321,S";
        frame_control(pFb,data.noise,data.flower,pos1,pos2);
    }
            FrameBuffDeInit(pFb);
    return NULL;
}

7、实现效果

软件搞定

8、总结

        软件部分大体都是有整体流程的,比较有规律,相对于代码,更复杂的应该是配置库和环境,需要使用大量时间去配置这些东西。等把硬件代码部分弄出来然后也分享出来。后面有时间会把上面学习到的东西,自己整理一下发出来。很多东西已经在笔记里面记好了,不过发CSDN文档改格式有点费时间,就一直没弄。我把这段时间看过的文档和书艾特在下面了。

9、参考内容

书籍没有全部看完,所以还是各取所需,更多时候都是看的文章。文章这里很多,有很多都忘记看的哪些了

书:

  1. Linux命令行大全
  2. Linux网络编程
  3. 计算机网络(谢希仁第五版)
  4. 大话数据结构

文章:

  1. Linux FrameBuffer(一) —— FrameBuffer是什么?怎么用?-CSDN博客

  2. Linux线程邮箱-CSDN博客

  3. sqlite3入门基础、sqlite3常用函数_sqlite3函数-CSDN博客       等等

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1556482.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

摸鱼的时候可以干什么?

可以做什么&#xff1f;有了VScode&#xff0c;你想做啥都可以&#xff01; 1、刷知乎 上班总是忍不住刷知乎&#xff0c;但是又怕领导发现&#xff0c;这个插件可以帮助你悄无声息地愉快地浏览知乎&#xff0c;有多少人是用这款插件看到的这篇文章&#xff1f; 你甚至可以用 M…

Java反序列化JDK动态代理的关系

Java代理模式 为什么要学习代理模式&#xff1f;了解开发原理&#xff0c;才能明白漏洞的产生。这不仅仅是SpringAOP的底层&#xff01; [SpringAOP 和 SpringMVC] 代理模式的分类&#xff1a; 静态代理动态代理 静态代理 角色分析&#xff1a; 抽象角色&#xff1a;一般会…

【vue】一个小bug和key的引入

点击master Vue!删除后该list后输入框中的Jerry消失了 原因&#xff1a;vue当你更改元素时会在真实的dom中渲染并更新list。这两个goal是两个dom元素,触发点击事件后,vue并不会删除第一个dom元素,而是把第二个dom元素的动态内容({{ goal }} - {{ index }})复制到第一个dom元素…

Logback日志框架(超详细)

logback-classic-1.2.3.jarhttp://链接: https://pan.baidu.com/s/1cA3gVB_6DEA-cSFJN6MDGw 提取码: sn8i 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 logback-core-1.2.3.jarhttp://链接: https://pan.baidu.com/s/19eCsvsO72a9PTqpXvXxrgg 提取码: 5yp…

JHY-31复合电压继电器 额定电压Un=110VDC 板后接线 JOSEF约瑟

用途&#xff1a; JHY-31复合电压继电器使用于电力系统的继电保护线路中&#xff0c;作为各种类型故障的判别元件和电压闭锁元件。 继电器型号名称&#xff1a; 例:辅助直流工作电压为110V的复合电压继电器的订货代号为: JHY-31/110V。 工作原理&#xff1a; 继电器内部具有负…

云架构(二) 大使模式

Ambassador pattern &#xff08;https://learn.microsoft.com/en-us/azure/architecture/patterns/ambassador&#xff09; 简单描述 创建一个助手服务&#xff0c;这个服务代表消费服务或者应用程序发送网络请求。大使服务可以看做是与客户机同一个位置的进程外代理。 这种…

【JDK常用的API】包装类

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …

微服务(基础篇-007-RabbitMQ)

目录 初识MQ(1) 同步通讯&#xff08;1.1&#xff09; 异步通讯&#xff08;1.2&#xff09; MQ常见框架&#xff08;1.3&#xff09; RabbitMQ快速入门(2) RabbitMQ概述和安装&#xff08;2.1&#xff09; 常见消息模型&#xff08;2.2&#xff09; 快速入门&#xff…

精品丨PowerBI负载测试和容量规划

当选择Power BI作为业务报表平台时&#xff0c;如何判断许可证的选择是否符合业务需求&#xff0c;价格占了主导因素。 Power BI的定价是基于SKU和服务器内核决定的&#xff0c;但是很多IT的负责人都不确定自己公司业务具体需要多少。 不幸的是&#xff0c;Power BI的容量和预期…

短剧App开发:打造移动端的精彩剧情盛宴

在快节奏的生活中&#xff0c;人们对于娱乐内容的需求日益旺盛&#xff0c;短剧作为一种新兴的影视形式&#xff0c;以其紧凑的剧情、生动的表演和精彩的情节&#xff0c;受到了广大观众的喜爱。为了满足广大用户对短剧内容的渴望&#xff0c;我们倾力打造了一款全新的短剧App&…

02_在VM虚拟机创建Win7系统

一、镜像 Windows 7 Ultimate with Service Pack 1 (x64) - DVD (Chinese-Simplified) 二、新建虚拟机 选择下载的win7系统镜像&#xff0c;.ISO结尾的文件。 选择系统版本 选择名称和位置

概率论经典题目-二维随机变量及分布--求离散型的联合分布律和边缘分布律问题

题目&#xff1a;一整数N等可能地在1,2,3,…,10十个值中取一个值设DD(N)是能整除N的正整数的个数,FF(N)是能整除N的素数的个数(注意1不是素数).试写出D和F的联合分布律,并求边缘分布律&#xff1f; 解答&#xff1a; 1&#xff09;要确定整数 N 能够被整除的正整数个数 D 和素…

线上废品回收小程序开发,线上回收成为大众“新宠”

随着全球回收意识的提高&#xff0c;废品回收已经成为了一个热门话题&#xff0c;在可持续发展下&#xff0c;回收市场领域有着巨大的发展前景。 如今&#xff0c;回收市场也进入到了互联网潮流中&#xff0c;互联网和数字化技术的发展对回收行业的发展起到了很大推动作用。回…

【Go】三、Go指针

文章目录 1、指针2、说明 1、指针 &符号变量 就可以获取这个变量内存的地址*int 是一个指针类型 &#xff08;可以理解为 指向int类型的指针&#xff09; package main import("fmt" ) func main(){var age int 18//&符号变量 就可以获取这个变量内存的地…

聚观早报 | 小米SU7正式发布;xAI推出Grok-1.5

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 3月30日消息 小米SU7正式发布 xAI推出Grok-1.5 红魔9 Pro新品亮相 长城汽车2023年营收 快狗打车2023年度业绩 小…

UWB辅助RTK如何应对极端环境

1.UWB定位 - UWB&#xff08;Ultra-Wideband&#xff09;是一种无线通信技术&#xff0c;其特点是具有较宽的频带&#xff0c;可以提供0.1-0.5m高精度的距离测量。 - UWB定位需要四台基站&#xff08;每台基站视距间隔50-100米&#xff09;呈矩形安装部署&#xff0c;以实现…

springboot婚庆系统

摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于婚庆系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了婚庆系统&#xff0c;它彻底改变了过去传统的管理方式…

vue3+vite 模板vue3-element-admin框架如何关闭当前页面跳转 tabs

使用模版: 有来开源组织 / vue3-element-admin 需要关闭的.vue 页面增加以下方法 //setup 里import {LocationQuery, useRoute, useRouter} from "vue-router"; const router useRouter(); function close() {console.log(|--router.currentRoute.value, router.cur…

五、postman基础使用案例

postman基础使用 相关案例【传递查询参数】【提交表单数据】【提交JSON数据】 注&#xff1a;postman⼀款⽀持调试和测试的⼯具&#xff0c;开发、测试⼯程师都可以使⽤。方法一般统一为&#xff1a;方法→请求头→请求体→断言 相关案例 【传递查询参数】 访问TPshop搜索商品的…

ElasticSearch、java的四大内置函数式接口、Stream流、parallelStream背后的技术、Optional类

第四周笔记 一、ElasticSearch 1.安装 apt-get install lrzsz adduser -m es 创建用户组&#xff1a; useradd *-m* xiaoming(用户名) *PS&#xff1a;追加参数-m* passwd xiaoming(用户名) passwd xiaoming 输入新的 UNIX 密码&#xff1a; 重新输入新的 UNIX 密码&…