質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

1回答

6034閲覧

c言語によるXMODEMなどの実装と送受信について

NEWBIEEBIEE

総合スコア62

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2016/12/31 21:08

編集2017/01/01 02:02

RaspberryPI上で下記のコードを動かしたいのですが、全く動きません。
コンパイルは通ってます。
XMODEMをいう規格でファイルの送受信を行いたいのですが、普通のxmodemと違うのは1度送信したデータを2回立て続けに再送するところです。
片方向のデータ送信のみしか許されない状況下での通信を想定しており、
受信側ではチェックサムなどから受信したデータの整合性について多数決で決めています。

terminal でmain関数内にxmodem_receiveを実行するプログラムとxmodem_sendを実行するプログラムをそれぞれtty/USB0とtty/AMA0を指定して実行します。保存先のファイルが開かれますが0バイトのままで、なんの変化もありません。送受信についてはpython の簡単なテキスト送受信プログラムで確認できています。

ちょっとだけでもいいので、受信と送信ができているところがみたいです。

C言語

1#include <stdio.h> 2#include <stdlib.h> 3#include <stdint.h> 4#include <string.h> 5#include <errno.h> 6#include <unistd.h> 7#include <fcntl.h> 8#include <termios.h> 9#include <sys/types.h> // 10#include <sys/stat.h> // 送受信ファイルの状態 11#include <sys/mman.h> // メモリ管理 12 13 14#define X_STX 0x02 15#define X_EOT 0x04 16#define X_ACK 0x06 17#define X_NAK 0x15 18 19#define min(a, b) ((a) < (b) ? (a) : (b)) 20 21#define DEBUG 0 22 23struct xmodem_chunk { 24 uint8_t start; 25 uint8_t blk; 26 uint8_t blk_neg; 27 uint8_t payload[1024]; 28 uint16_t crc; 29} __attribute__((packed));// メモリとアドレスのアライン(連続させる) 30 31#define CRC_POLY 0x1021 32 33/* 'Safe' write */ 34int safewrite(int fd, const void *p, size_t want){ 35 int ret; 36 int ret_sum = 0; 37 38 errno = 0; 39 while(want){ 40 ret = write(fd, (uint8_t *)p,want); 41 if(ret <= 0) { 42 if (errno != EINTR && errno != EAGAIN){ 43 return -1; 44 } 45 errno = 0; 46 continue; 47 } 48 want -= ret; 49 p = (uint8_t*) p + ret; 50 ret_sum += ret; 51 } 52 return ret_sum; 53} 54 55int saferead(int fd, const void *p, size_t want){ 56 int ret; 57 int ret_sum = 0; 58 59 errno = 0; 60 while (want){ 61 ret = read(fd, (uint8_t*)p, want); 62 if(ret == 0) 63 return -1; /* EOF */ 64 if(ret <= 0){ 65 if(errno != EINTR && errno != EAGAIN ) { 66 return -1; 67 } 68 errno = 0; 69 continue; 70 } 71 want -= ret; 72 p = (uint8_t*) p + ret; 73 ret_sum += ret; 74 } 75 return ret_sum; 76} 77 78static uint16_t crc_update(uint16_t crc_in, int incr) 79{ 80 uint16_t xor = crc_in >> 15; 81 uint16_t out = crc_in << 1; 82 83 if(incr) 84 out++; 85 86 if(xor) 87 out ^= CRC_POLY; // xor 0b1000000100001 88 89 return out; 90} 91 92/** 93* CRCを計算する(バッファされたデータを一気に計算) 94* 95* CRC-16-CCITT計算 96* 生成多項式=x^16+x^12+x^5+1 (除数 97*/ 98static uint16_t crc16(const uint8_t *data, uint16_t size) // データのチャンク8botづつに対しての処理 99{ 100 uint16_t crc, i; 101 102 for(crc = 0; size > 0; size--, data++) // >>= は複合代入演算子、 a = a >> b;と同じである 103 for(i = 0x80; i; i >> 1) 104 crc = crc_update(crc, *data & i); // 8ビットデータ本体のチャンクに対して上位4bitがすべて1の場合はCRC_POLYでxor 105 106 for ( i = 0; i < 16; i++) 107 crc = crc_update(crc, 0); 108 109 return crc; 110} 111static uint16_t swap16(uint16_t in) // 16bitの内上位8bit下位8bitの入れ替え 112{ 113 return (in >> 8) | ((in & 0xff) << 8); 114} 115 116enum { 117 PROTOCOL_XMODEM, 118 PROTOCOL_YMODEM, 119}; 120 121static int xymodem_send(int serial_fd, const char *filename) 122{ 123 size_t len; // ファイルのサイズ 124 int ret, fd; 125 uint8_t answer; 126 struct stat stat; 127 const uint8_t *buf; // 128 uint8_t eof = X_EOT; // データをすべて送信した際の符号 129 struct xmodem_chunk chunk; // ファイルの一部を入れるデータチャンク 130 int skip_payload = 0; 131 132 fd = open(filename, O_RDONLY); // ファイルディスクリプタの取得 133 if(fd < 0){ // ファイルディスクリプタが0以下ならエラー 134 perror("open"); 135 return -errno; 136 } 137 138 139 fstat(fd, &stat); // ファイルの状態の取得 140 len = stat.st_size; // ファイルサイズを取得 141 buf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); //仮想空間の作成 マッピングを行う。 メモリー保護は読み込み可能(PROT_READ)で同じファイルをマッピングしているほかプロセスに対して更新が見えず、更新がマッピング元のファおるに伝わることもない。 142 143 if(!buf){ // mmapでマップ領域のポインタが介されない場合 144 perror("mmap"); 145 return -errno; 146 } 147 148 149 printf("Sending %s ", filename); 150 151 chunk.start = X_STX; //最初のスタートビット 152 153 while (len){ 154 size_t z = 0; 155 int next = 0; 156 char status; 157 158 z = min(len, sizeof(chunk.payload)); // ファイルの長さがチャンク以下ならチャンクにその長さで入れる 159 memcpy(chunk.payload, buf, z); 160 memset(chunk.payload + z, 0xff, sizeof(chunk.payload) - z); // 161 162 chunk.crc = swap16(crc16(chunk.payload, sizeof(chunk.payload))); 163 chunk.blk_neg = 0xff - chunk.blk; // 降順でデータに送付するブロック 164 int i; 165 for(i = 0; i < 3; i++){ 166 ret = safewrite(serial_fd, &chunk, sizeof(chunk)); // 書き込まれたバイト数を返す 167 if(ret != sizeof(chunk)){ 168 return -errno; 169 } 170 } 171 172 if(next){ 173 chunk.blk++; 174 len -= z; 175 buf += z; 176 } 177 } 178 for(int i = 0; i < 3; i++){ 179 ret = safewrite(serial_fd, &eof, sizeof(eof)); 180 if(ret != sizeof(eof)) 181 return -errno; 182 } 183 printf("done.\n"); 184 return 0; 185} 186 187static xmodem_receive(int serial_fd, char* filename){ 188 size_t len; 189 int ret; 190 size_t retry; 191 struct xmodem_chunk chunk; 192 struct stat stat; 193 int file_size=0; 194 FILE *fp; 195 size_t ch_size = sizeof(chunk); 196 197 int eof_count=0; 198 199 200 retry = 3; 201 /* バイナリ書き込み読み込みモードでファイルをオープン */ 202 fp = fopen(filename, "ab+"); 203 204 205 while(1){ 206 207 int v_stx_count=0; 208 int inv_stx_count=0; 209 int garbage_blk_count=0; 210 int correct_blk_count=0; 211 int garbage_count=0; 212 int correct_count=0; 213 uint8_t chunk_payload[1024]; 214 uint8_t garbage_payload[3][1024]; 215 uint16_t garbage_crc[3]; 216 int val_payload_crc_pr = 0; 217 int val_payload_crc_cr = 0; 218 int val_payload_crc_nx = 0; 219 int pr_val_crc=0; 220 int nx_val_crc=0; 221 222 int val_crc=0; 223 size_t z = 0; 224 while(retry){ 225 226 int next = 0; 227 228 ret = saferead(serial_fd, &chunk, ch_size); 229 printf("チャンクを受け取りました"); 230 z = sizeof(chunk.payload); 231 if(chunk.start != X_STX){ 232 printf("error STX\n"); 233 return 0; // error 234 } 235 printf("retry part\n"); 236 if(chunk.crc != swap16(crc16(chunk.payload, sizeof(chunk.payload)))){ // チャンクがごみかどうか 237 if(garbage_count > 1){ 238 int i; 239 for(i=0; i < garbage_count; i++){ 240 // ごみからあたりを見つける 241 if(chunk.crc == swap16(crc16(garbage_payload[i], sizeof(chunk.payload)))){ 242 correct_count++; 243 memcpy(chunk_payload, garbage_payload[i], len); 244 } 245 } 246 if(correct_count < 1){ 247 memcpy(garbage_payload[garbage_count], &chunk.payload, len); 248 garbage_count++; 249 } 250 printf("garbage#1\n"); 251 }else{ 252 // ごみの登録 253 memcpy(garbage_payload[0], &chunk.payload, len); 254 garbage_crc[0] = chunk.crc; 255 garbage_count++; 256 printf("garbage#2\n"); 257 } 258 259 260 }else{ 261 printf("correct\n"); 262 correct_count++; 263 memcpy(chunk_payload , &chunk.payload, len); 264 } 265 retry--; 266 267 268 } 269 safewrite(fp, &chunk_payload, z); 270 271 272 } 273 close(fp); 274 return 0; 275} 276 277static int open_serial(const char *path, int baud) 278{ 279 int fd; 280 struct termios tty; 281 282 fd = open(path, O_RDWR | O_SYNC); 283 if(fd < 0) { 284 perror("open"); 285 return -errno; 286 } 287 288 memset(&tty, 0, sizeof(tty)); 289 if(tcgetattr(fd, &tty) != 0) { 290 perror("tcgetattr"); 291 return -errno; 292 } 293 294 cfsetospeed(&tty, baud); 295 cfsetispeed(&tty, baud); 296 297 tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit 298 tty.c_iflag &= ~IGNBRK; // disable break processing 299 tty.c_lflag = 0; // nosignaling chars, no echo, 300 // no canonical processing 301 tty.c_oflag = 0; // no remapping, no delays 302 tty.c_cc[VMIN] = 1; // read doesn't block 303 tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout 304 305 tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl 306 307 tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controlsm 308 309 tty.c_cflag &= ~(PARENB | PARODD); // ignore modem controls, 310 // enable reading 311 tty.c_cflag &= ~(PARENB | PARODD); // shut off party 312 tty.c_cflag &= ~CSTOPB; 313 tty.c_cflag &= ~CRTSCTS; 314 315 if (tcsetattr(fd, TCSANOW, &tty) != 0) { 316 perror("tcsetattr"); 317 return -errno; 318 } 319 320 return fd; 321} 322 323static void dump_serial(int serial_fd) 324{ 325 char in; 326 327 for (;;) { 328 read(serial_fd, &in, sizeof(in)); 329 printf("%c", in); 330 fflush(stdout); 331 } 332} 333 334int main(int argc, char **argv){ 335 int ret, serial_fd; 336 337 serial_fd = open_serial("/dev/ttyUSB0", 115200); 338 339 340 ret = xmodem_receive(serial_fd, "sample.jpg"); 341 342} 343

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

全く動かないというのがどのような状況なのかが不明です。
printfが所々にありますが、実行するとどのあたりまで想定通りの
出力がありますか?

投稿2017/01/01 01:28

otaks

総合スコア223

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

NEWBIEEBIEE

2017/01/01 02:02

返信ありがとうございます。terminal でmain関数内にxmodem_receiveを実行するプログラムとxmodem_sendを実行するプログラムをそれぞれtty/USB0とtty/AMA0を指定して実行します。保存先のファイルが開かれますが0バイトのままで、なんの変化もありません。送受信についてはpython の簡単なテキスト送受信プログラムで確認できています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問