Raspberry Piでソケット通信


 前回、再セットアップをして復旧したRaspberry Pi2です。

 今回はこのRaspberry Pi2でイーサネットを使ってPCとソケット通信行うプログラムを実装しました。
 ソケット通信を使うと、PCやスマホ、他のマイコンボード等のイーサネットに接続できるシステムとデータ通信を行うことができます。Raspberry Piに対してPCのコントロールアプリから指令を送ったり、Raspberry Pi側で収集したデータをPC側に返したりといった通信処理が簡単に実装できます。特にRaspberry Piはwifiを使って簡単に無線化できますので、色々なアプリに応用できるかと思います。

今回実装したソースコードは下記の通りです。

#include <stdio.h>
#include <sys/time.h>									//nanosleepで使用
//マルチスレッド
#include <pthread.h>
//ソケット通信
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
//SPI
#include <wiringPiSPI.h>
#include <wiringPi.h>

//////////////////////////////////
/*	構造体宣言		*/
//////////////////////////////////
//ソケット通信転送用構造体
typedef struct {
    float prm_pc_to_soc[20];								//PC→SoCへの転送パラメータ
    float prm_soc_to_pc[20];								//SoC→PChへの転送パラメータ
} Transfer_data;

//////////////////////////////////
/*	グローバル変数		*/
//////////////////////////////////

//ソケット通信データ
static float g_sock_recv[20];								//PCからの受信データ
static float g_sock_send[20];								//PCへの送信データ

//////////////////////////////////
/*	マルチスレッド		*/
//////////////////////////////////
void* thread1(void* pParam); //スレッド1
//void* thread2(void* pParam); //スレッド2

int main(void)
{
	//スレッド変数
	pthread_t tid1;									//メインスレッド
	pthread_t tid2;									//ソケット通信
	
	//////////////////////////////////
	/*	マルチスレッド		*/
	//////////////////////////////////
	//スレッド作成(第4ポインタがスレッドへの引数) 使用する機能によりアクティブにするスレッドを選択
	pthread_create(&tid1, NULL, thread1, NULL);					//ソケット通信処理
	//pthread_create(&tid2, NULL, thread2, NULL);					//SPI通信
	
	pthread_join(tid1, NULL);							//ソケット通信処理
	//pthread_join(tid2, NULL);							//SPI通信
	
	return 0;
}

//スレッド1 ソケット通信処理
void* thread1(void* pParam)
{
	int sock0;
	struct sockaddr_in addr;
	struct sockaddr_in client;
	int len;
	int sock;
	int yes = 1;
	
	//パラメータ転送構造体
	Transfer_data td_recv;
	Transfer_data td_send;
	
	//転送テスト用
	float test_wm1 = 60;
	float test_wm2 = 250;
	float test_wm3 = 333;
	float test_wm4 = 444;
	float test_wm5 = 555;
	float test_wm6 = 666;
	float test_wm7 = 777;
	float test_wm8 = 888;
	float test_wm9 = 999;
	float test_wm10 = 1000;

	//ソケット作成
	sock0 = socket(AF_INET, SOCK_STREAM, 0);
	
	//ソケット作成エラーチェック
	if(sock0 < 0) {
		perror("socket");
		return -1;
	}
	printf( "make socket...\n" );

	addr.sin_family = AF_INET;
	addr.sin_port = htons(12345);
	addr.sin_addr.s_addr = INADDR_ANY;						//ワイルドカードアドレスを指定(どのIPでも接続可)
	
	//ソケットのオプション設定
	setsockopt(
			sock0,
			SOL_SOCKET,							//API層でオプションを操作
			SO_REUSEADDR,							//オプションを指定
			(const char *)&yes,						//オプションの値を格納したバッファ
			sizeof(yes)							//バッファのサイズ
		);
	
	//アドレスとソケットディスクリプタを関連付け
	if (bind(sock0, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
		perror("bind");
		return -1;
	}
	
	printf( "bind...\n" );
	
	//接続待ちに設定(acceptにて接続要求を受ける)
	if(listen(sock0, 5) != 0) {
		perror("listen");
		return -1;
	}
	
	printf( "listen...\n" );
	
	printf( "accept loop...\n" );
	
	//接続要求待ちループ
	while (1) {
		len = sizeof(client);
		sock = accept(sock0, (struct sockaddr *)&client, &len);
		
		//接続エラー判定
		if (sock < 0) {
			//エラー時はループを抜けて処理を終了
			perror("accept");
			break;
		}
		
		//受信用バッファ用意
		memset((void *)&td_recv, 0, sizeof(td_recv));
		
		//データ受信
		recv(sock, (void *)&td_recv, sizeof(td_recv), 0);
		
		//データコピー
		memcpy(g_sock_recv, td_recv.prm_pc_to_soc, sizeof(float) * 20);		//受信データをPWM指令用バッファへコピー
		
		//受信したデータを画面に出力
		printf("pwm1 = %f\n", td_recv.prm_pc_to_soc[0]);
		printf("pwm2 = %f\n", td_recv.prm_pc_to_soc[1]);
		printf("pwm3 = %f\n", td_recv.prm_pc_to_soc[2]);
		printf("pwm4 = %f\n", td_recv.prm_pc_to_soc[3]);
		printf("servo pwm1 = %f\n", td_recv.prm_pc_to_soc[4]);
		
		//転送データ
		g_sock_send[0] = test_wm1;
		g_sock_send[1] = test_wm2;
		g_sock_send[2] = test_wm3;
		g_sock_send[3] = test_wm4;
		g_sock_send[4] = test_wm5;
		g_sock_send[5] = test_wm6;
		g_sock_send[6] = test_wm7;
		g_sock_send[7] = test_wm8;
		g_sock_send[8] = test_wm9;
		g_sock_send[9] = test_wm10;
		
		//転送データコピー
		memcpy(td_send.prm_soc_to_pc, g_sock_send, sizeof(float) * 20);
		
		//データ送信送信
		send(sock, (char *)&td_send, sizeof(td_send), 0);
		
	}
	
	printf( "End of communication...\n" );
	
	//ソケットクローズ
	close(sock0);
	
	printf( "Close socket...\n" );
	
	return 0;
}

//スレッド2 SPI通信処理
//void* thread2(void* pParam)
//{
//}

 通信するデータはfloat型のデータを20個相互に送受信する仕様になっています。処理内容は以前このブログで乗せたAltera SoCのソケット通信プログラムをそのまま流用しています。
・ソケット通信のプログラム(マイコン側)

 このソースコードではRaspberry Pi側がサーバー、接続先がクライアントとなります。ちなみにこのRaspberry Piは、今後ソケット通信の他にもFPGAボードとのSPI通信等も実装する予定なので、マルチスレッドで実装しました。とりあえず現時点ではスレッドは1つだけで2つ目のSPI通信用のスレッドは今回はコメントアウトしてあります。

次回はこのプログラムで実際にPCと通信させた結果を書きたいと思います。

Add a Comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です