OSDN Git Service

Moved some unused codes.
[kozos-expbrd/kozos_expbrd.git] / misc / hwtest / tools / kz_h8write / mot.c
1 /**
2  * @file mot.c
3  * @author Shinichiro Nakamura
4  * @brief motファイルモジュールの実装。
5  */
6
7 /*
8  * ===============================================================
9  *  mot file interface library
10  *  Version 0.0.3
11  * ===============================================================
12  * Copyright (c) 2010-2011 Shinichiro Nakamura
13  *
14  * Permission is hereby granted, free of charge, to any person
15  * obtaining a copy of this software and associated documentation
16  * files (the "Software"), to deal in the Software without
17  * restriction, including without limitation the rights to use,
18  * copy, modify, merge, publish, distribute, sublicense, and/or
19  * sell copies of the Software, and to permit persons to whom the
20  * Software is furnished to do so, subject to the following
21  * conditions:
22  *
23  * The above copyright notice and this permission notice shall be
24  * included in all copies or substantial portions of the Software.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
28  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
30  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
31  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
33  * OTHER DEALINGS IN THE SOFTWARE.
34  * ===============================================================
35  */
36
37 #include "mot.h"
38 #include <stdio.h>
39 #include <string.h>
40 #include <ctype.h>
41
42 /**
43  * @brief 文字列に含まれる制御コードを取り除く。
44  * @details
45  * この関数は制御コードを見つけるとNULLに置き換える。
46  * 文字列の途中に制御コードが見つかった場合、
47  * それはNULLとなり文字列の終端となる。
48  * 文字列の途中に制御コードが含まれるケースを今回は
49  * 考慮する必要はない。
50  */
51 static void text_trim(char *txt) {
52     const int len = strlen(txt);
53     for (int i = 0; i < len; i++) {
54         if ((txt[i] == '\r') || (txt[i] == '\n') || (txt[i] == '\t')) {
55             txt[i] = '\0';
56         }
57     }
58 }
59
60 /**
61  * @brief 与えられた文字を16進数として解釈し値を得る。
62  * @param c 文字。
63  * @retval 0以上 値。
64  * @retval 負値 エラー。
65  */
66 static unsigned int get_hex_num(const char c) {
67     static const char *hextxt = "0123456789ABCDEF";
68     for (int i = 0; i < 16; i++) {
69         if (c == hextxt[i]) {
70             return i;
71         }
72     }
73     return -1;
74 }
75
76 /**
77  * @brief 1レコードをパースする。
78  * @param p mot構造体。(コールバック関数などの情報を参照する。)
79  * @param txt 1レコード。
80  * @retval 0 成功
81  * @retval 0以外 エラー番号。
82  */
83 static int parse_record(mot_t *p, const char *txt)
84 {
85     unsigned char buf[BUFSIZ];
86
87     /*
88      * 与えられた文字列は少なくとも4バイト長なければおかしい。
89      */
90     const int txtlen = strlen(txt);
91     if (txtlen < 4) {
92         return -1;
93     }
94
95     /*
96      * 最初の文字は必ずSでなければならない。
97      */
98     if (txt[0] != 'S') {
99         return -2;
100     }
101
102     /*
103      * 次の文字はレコードタイプである。
104      */
105     if (!isdigit(txt[1])) {
106         return -3;
107     }
108
109     /*
110      * その次の2バイトはレコードに含まれるアドレスからチェックサムまでのデータバイト数である。
111      * ここでバイト数とテキスト長を比較して正当なレコードであることを検証する。
112      */
113     const int datlen = (get_hex_num(txt[2]) * 0x10) + (get_hex_num(txt[3] * 0x01));
114     if ((datlen * 2) != txtlen - 4) {
115         return -4;
116     }
117
118     /*
119      * チェックサムを検証する。
120      * チェックサムはデータ長からチェックサムの前までの加算に対して1の補数をとったものである。
121      *
122      * 1. チェックサムの計算とデータの格納を行う。
123      * 2. チェックサムの妥当性を検証する。
124      *
125      * 同時に内部バッファ(buf)にデータをコピーする。
126      * 内部バッファ(buf)にはデータバイト数以降のデータが格納される。
127      */
128     unsigned char chksum = datlen;
129     for (int i = 0; i < datlen; i++) {
130         buf[i] = (get_hex_num(txt[4 + (i * 2)]) * 0x10) + (get_hex_num(txt[5 + (i * 2)] * 0x01));
131         if (i < datlen - 1) {
132             chksum += buf[i];
133         }
134     }
135     unsigned char verify = ~buf[datlen - 1];
136     if (chksum != verify) {
137         return -5;
138     }
139
140     /*
141      * 全てが妥当なデータと見なせる。
142      * よってコールバックを呼び出す。
143      * ここでレコードの種類によって呼び出す関数を分けることもできる。
144      *
145      * この関数に渡された元データのゼロから数えて第1バイト目がレコードの種類を示している。
146      */
147     switch (txt[1]) {
148         case '0':
149             /*
150              * スタートレコード。
151              */
152             // @todo 必要になったら実装する。
153             break;
154         case '1':
155             /*
156              * データレコード。(16ビットアドレスデータ)
157              */
158             if (p->cb_data != NULL) {
159                 unsigned int addr =
160                     (buf[0] * 0x00000100) +
161                     (buf[1] * 0x00000001);
162                 p->cb_data(addr, buf + 2, datlen - 2 - 1);
163             }
164             break;
165         case '2':
166             /*
167              * データレコード。(24ビットアドレスデータ)
168              */
169             if (p->cb_data != NULL) {
170                 unsigned int addr =
171                     (buf[0] * 0x00010000) +
172                     (buf[1] * 0x00000100) +
173                     (buf[2] * 0x00000001);
174                 p->cb_data(addr, buf + 3, datlen - 3 - 1);
175             }
176             break;
177         case '3':
178             /*
179              * データレコード。(32ビットアドレスデータ)
180              */
181             if (p->cb_data != NULL) {
182                 unsigned int addr =
183                     (buf[0] * 0x01000000) +
184                     (buf[1] * 0x00010000) +
185                     (buf[2] * 0x00000100) +
186                     (buf[3] * 0x00000001);
187                 p->cb_data(addr, buf + 4, datlen - 4 - 1);
188             }
189             break;
190         case '4':
191             /*
192              * シンボルレコード。
193              */
194             // @todo 必要になったら実装する。
195             break;
196         case '5':
197             /*
198              * データレコード数。
199              */
200             // @todo 必要になったら実装する。
201             break;
202         case '6':
203             /*
204              * 未使用。
205              */
206             // @todo 必要になったら実装する。
207             break;
208         case '7':
209             /*
210              * データレコード終了。(32ビットアドレスデータ)
211              */
212             // @todo 必要になったら実装する。
213             break;
214         case '8':
215             /*
216              * データレコード終了。(24ビットアドレスデータ)
217              */
218             // @todo 必要になったら実装する。
219             break;
220         case '9':
221             /*
222              * データレコード終了。(16ビットアドレスデータ)
223              */
224             // @todo 必要になったら実装する。
225             break;
226         default:
227             /*
228              * 不明なデータ。
229              */
230             break;
231     }
232
233     return 0;
234 }
235
236 /**
237  * @brief motファイルを読み込む。
238  *
239  * @param filename ファイル名。(NULLを与えると標準入力を入力とする。)
240  * @param p mot構造体。(コールバック関数などの情報を参照する。)
241  *
242  * @retval 0 成功
243  * @retval 0以外 エラー番号。
244  */
245 int mot_read(const char *filename, mot_t *p)
246 {
247     char buf[BUFSIZ];
248     FILE *fp = NULL;
249
250     if (filename == NULL) {
251         /*
252          * 標準入力を入力用ファイルとして用いる。
253          */
254         fp = stdin;
255         if (fp == NULL) {
256             return -1;
257         }
258     } else {
259         /*
260          * ファイルをオープンする。
261          */
262         fp = fopen(filename, "r");
263         if (fp == NULL) {
264             return -1;
265         }
266     }
267
268     /*
269      * レコードを1つずつ読み込んでパースする。
270      */
271     while (fgets(buf, sizeof(buf), fp)) {
272         const int len = strlen(buf);
273         if (len > 0) {
274             text_trim(buf);
275             if (parse_record(p, buf) != 0) {
276                 fclose(fp);
277                 return -2;
278             }
279         }
280     }
281
282     /*
283      * ファイルをクローズする。
284      */
285     fclose(fp);
286     return 0;
287 }
288