Fixed issue where the LRC of a card was the reverse of the start
[magread] / mslib.c
1 /*
2  * This file is part of mslib.
3  * mslib is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation, either version 3 of the License, or
6  * (at your option) any later version.
7  *
8  * mslib is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with nosebus.  If not, see <http://www.gnu.org/licenses/>.
15  */
16 #include "mslib.h"
17
18 /* Data Create/Free functions */
19 msData *_ms_create() {
20         msData *ms;
21
22         ms = ( msData * ) calloc( sizeof( msData ), 1 );
23         if ( !ms )
24                 return NULL;
25         ms->peakThreshold = PEAK_THRESHOLD;
26         ms->peakOffset = PEAK_OFFSET;
27
28         return ms;
29 }
30
31 msData *ms_create( const short *pcmData, int pcmDataLen ) {
32         msData *ms;
33
34         ms = _ms_create();
35         if( !ms )
36                 return NULL;
37         
38         ms->pcmData = ( short * )pcmData;
39         ms->pcmDataLen = pcmDataLen;
40
41         return ms;
42 }
43
44 msData *ms_free( msData *ms ) {
45         if( !ms )
46                 return NULL;
47         
48         if( ms->peakList )
49                 llist_free( ms->peakList );
50         
51         if( ms->bitStream )
52                 free( ms->bitStream );
53         
54         if( ms->charStream )
55                 free( ms->charStream );
56
57         free( ms );
58
59         return NULL;
60 }
61
62 void ms_reinit( msData *ms ) {
63         if( !ms )
64                 return;
65
66         if( ms->peakList ) {
67                 llist_free( ms->peakList );
68                 ms->peakList = NULL;
69         }
70         
71         if( ms->bitStream ) {
72                 free( ms->bitStream );
73                 ms->bitStream = NULL;
74         }
75
76         if( ms->charStream ) {
77                 free( ms->charStream );
78                 ms->charStream = NULL;
79         }
80 }
81
82 /* Misc User Functions */
83 void ms_set_peakThreshold( msData *ms, int peakThreshold ) {
84         if( !ms )
85                 return;
86         ms->peakThreshold = peakThreshold;
87 }
88
89 void ms_set_peakOffset( msData *ms, int peakOffset ) {
90         if( !ms )
91                 return;
92         ms->peakOffset = peakOffset;
93 }
94
95 const char *ms_get_bitStream( msData *ms ) {
96         if( !ms )
97                 return NULL;
98         return ms->bitStream;
99 }
100
101 const char *ms_get_charStream( msData *ms ) {
102         if( !ms )
103                 return NULL;
104         return ms->charStream;
105 }
106
107
108 /* Finding Peaks */
109 int ms_range( int a, int b1, int b2 ) {
110         if( ( a >= b1 && a <= b2 ) || ( a >= b2 && a <= b1 ) )
111                 return 1;
112         return 0;
113 }
114
115 #define RANGE_OFFSET 2
116 void ms_peaks_find( msData *ms ) {
117         int i;
118         short *pcmData, *pcmDataOffset;
119         
120         if( ms == NULL || ( ms->pcmData == NULL ) )
121                 return;
122         
123         if( ms->peakList == NULL )
124                 ms->peakList = llist_init();
125         else
126                 llist_reinit( ms->peakList );
127
128         pcmData = ms->pcmData + RANGE_OFFSET;
129         pcmDataOffset = pcmData + ms->peakOffset;
130
131         for( i = ms->peakOffset + RANGE_OFFSET; i < ms->pcmDataLen; i++, pcmData++, pcmDataOffset++ ) {
132                 if( abs( *pcmData ) > ms->peakThreshold &&
133                         ms_range( *pcmData, *( pcmDataOffset - RANGE_OFFSET ), *( pcmDataOffset + RANGE_OFFSET ) ) ) {
134
135                         llist_append( ms->peakList, i, ms->pcmData[ i ] );
136                 }
137         }
138 }
139
140 void ms_peaks_find_walk( msData *ms ) {
141         int i;
142         short *pcmData;
143
144
145         if( ms == NULL || ( ms->pcmData == NULL ) )
146                 return;
147                 
148         if( ms->peakList == NULL )
149                 ms->peakList = llist_init();
150         else
151                 llist_reinit( ms->peakList );
152
153         for( i = 0, pcmData = ms->pcmData; i+1 < ms->pcmDataLen; i++, pcmData++ ) {
154                 if( abs( *pcmData ) > ms->peakThreshold ) {
155                         if( abs( pcmData[ 1 ] ) < abs( *pcmData ) ) {
156                                 llist_append( ms->peakList, i, *pcmData );
157                         }
158                 }
159         }
160 }
161
162
163 void ms_peaks_filter_group( msData *ms ) {
164         LList *trav;
165         LListH *groupList;
166         
167         int pos;//indicates pos/neg (not position)
168
169         if( !ms || ms->peakList->len < 2 )
170                 return;
171         
172         pos = ( ms->peakList->first->amp > 0 );
173
174         groupList = llist_init();
175         for( trav = ms->peakList->first; trav != NULL; trav = trav->next ) {
176
177                 if( ( trav->amp > 0 ) != pos ) {
178                         pos = !pos;
179                         _ms_peaks_filter_groupFind( ms, groupList );
180                 }
181                 
182                 llist_append( groupList, trav->idx, trav->amp );
183         }
184
185         if( groupList->len )
186                 _ms_peaks_filter_groupFind( ms, groupList );
187         
188         groupList = llist_free( groupList );
189 }
190
191
192
193 LListH *_ms_peaks_filter_groupFind( msData *ms, LListH *groupList ) {
194         LList *trav;
195         struct {
196                 int idx;
197                 short amp;
198         } bigPeak;
199
200         if( !ms || groupList == NULL || groupList->len < 2 )
201                 return NULL;
202         
203         bigPeak.idx = groupList->first->idx;
204         bigPeak.amp = abs( groupList->first->amp );
205
206         for( trav = groupList->first->next; trav != NULL; trav = trav->next ) {
207                 if( abs( trav->amp ) > bigPeak.amp ) {
208                         llist_remove_idx( ms->peakList, bigPeak.idx );
209                         bigPeak.idx = trav->idx;
210                         bigPeak.amp = abs( trav->amp );
211                 } else {
212                         llist_remove_idx( ms->peakList, trav->idx );
213                 }
214         }
215
216         llist_reinit( groupList );
217         return groupList;
218 }
219
220
221 /* Peak Decode functions */
222 char _ms_closer( int *oneClock, int dif ) {
223         int oneDif = abs( *oneClock - dif );
224         int zeroDif = abs( ( *oneClock * 2 ) - dif );
225         char bit;
226
227         if( oneDif < zeroDif ) {
228                 *oneClock = dif;
229                 bit = '1';
230         } else {
231                 *oneClock = dif / 2;
232                 bit = '0';
233         }
234
235         return bit;
236 }
237
238 void ms_decode_peaks( msData *ms ) {
239         LList *trav;
240         int clock, len;
241         int lastPeakidx;
242         char lastBit, curBit, bitStream[ MAX_BITSTREAM_LEN + 1 ];
243
244         if( !ms || ms->peakList == NULL || ms->peakList->len < 3 )
245                 return;
246
247         if( ms->bitStream ) {
248                 free( ms->bitStream );
249                 ms->bitStream = NULL;
250         }
251         
252         lastPeakidx = ms->peakList->first->next->idx;
253         clock = ( ms->peakList->first->next->next->idx - lastPeakidx ) / 2;
254
255         len = 0;
256         lastBit = '\0';
257
258         for( trav = ms->peakList->first->next; trav != NULL && len < MAX_BITSTREAM_LEN; trav = trav->next ) {
259                 curBit = _ms_closer( &clock, ( trav->idx - lastPeakidx ) );
260                 if( curBit == '0' ) {
261                         bitStream[ len++ ] = curBit;
262                 } else if( curBit == lastBit ) {
263                         bitStream[ len++ ] = curBit;
264                         curBit = '\0';
265                 }
266                 
267                 lastBit = curBit;
268                 lastPeakidx = trav->idx;
269         }
270
271         bitStream[ len ] = '\0';
272
273         ms->bitStream = ( char * ) malloc( sizeof( char ) * strlen( bitStream ) + 1 );
274         strcpy( ms->bitStream, bitStream );
275 }
276
277 /* String Reverse Function */
278 void ms_strrev( char *str ) {
279         int f, l;
280         char tmp;
281
282         for( f = 0, l = strlen( str ) - 1; l > f; f++, l-- ) {
283                 tmp = str[ f ];
284                 str[ f ] = str[ l ];
285                 str[ l ] = tmp;
286         }
287 }
288
289 /* Bit Decode functions */
290 int ms_decode_typeDetect( msData *ms ) {
291         char *bitStream;
292         int loop = 2;
293
294         if( !ms || !ms->bitStream || strlen( ms->bitStream ) < 10 )
295                 return 1;
296
297         do {
298                 bitStream = strchr( ms->bitStream + 5, '1' );
299                 if( bitStream == NULL )
300                         break;
301         
302                 if( !strncmp( bitStream, ABA_SS, ABA_CHAR_LEN ) && strncmp( bitStream, ABA_SS ABA_ES, ABA_CHAR_LEN * 2 ) ) {
303                         ms->dataType = ABA;
304                         return 0;
305                 } else if( !strncmp( bitStream, IATA_SS, IATA_CHAR_LEN ) && strncmp( bitStream,IATA_SS IATA_ES, IATA_CHAR_LEN * 2 ) ) {
306                         ms->dataType = IATA;
307                         return 0;
308                 }
309
310                 ms_strrev( ms->bitStream );
311                 loop--;
312         } while( loop );
313
314         ms->dataType = UNKNOWN;
315         return 1;
316 }
317
318
319 int ms_decode_bits( msData *ms ) {
320         char *bitStream;
321         char charStream[ MAX_IATA_LEN + 1 ], curChar;
322         char LRC[ IATA_CHAR_LEN ] = { 0 };
323         int bitStreamLen, i, x, len, validSwipe;
324         int maxLen, charLen, badChars;
325
326         if( !ms || !ms->bitStream )
327                 return -1;
328
329         if( ms_decode_typeDetect( ms ) )
330                 return -1;
331
332         if( ms->dataType == ABA ) {
333                 maxLen = MAX_ABA_LEN;
334                 charLen = ABA_CHAR_LEN;
335         } else {
336                 maxLen = MAX_IATA_LEN;
337                 charLen = IATA_CHAR_LEN;
338         }
339
340         if( ms->charStream ) {
341                 free( ms->charStream );
342                 ms->charStream = NULL;
343         }
344
345         validSwipe = 0;
346
347         bitStream = strchr( ms->bitStream, '1' );
348         if( bitStream == NULL ) // if stream contains no 1s, it's bad, just quit
349                 return 1;
350         
351         bitStreamLen = strlen( bitStream );
352
353         /* Traverse the bitstream to decode all the bits into a charstream */
354         curChar = '\0';
355         badChars = 0;
356         for( i = 0, len = 0; ( i + charLen ) < bitStreamLen && len < maxLen && curChar != '?'; i += charLen, len++ ) {
357                 curChar = _ms_decode_bits_char( bitStream + i, LRC, ms->dataType );
358                 charStream[ len ] = curChar;
359                 if( curChar == BAD_CHAR )
360                         badChars++; // count the bad chars
361         }
362         charStream[ len ] = '\0';
363
364         /* Print warning about any detected bad characters */
365         if( badChars ) {
366                 fprintf( stderr, "ms_decode_bits(): Warning: %d chars failed parity check\n", badChars );
367                 validSwipe = 1;
368         }
369
370         ms->charStream = ( char * ) malloc( sizeof( char ) * strlen( charStream ) + 1 );
371         strcpy( ms->charStream, charStream );
372         if( !ms->charStream )
373                 return 1;
374         
375
376         /* Calculate the parity bit for the LRC */
377         LRC[ ( charLen - 1 ) ] = 1;
378         for( x = 0; x < ( charLen - 1 ); x++ ) {
379                 if( LRC[ x ] == 1 )
380                         LRC[ ( charLen - 1 ) ] = !LRC[ ( charLen - 1 ) ];
381                 LRC[ x ] += NUM_ASCII_OFFSET;
382         }
383         LRC[ ( charLen - 1 ) ] += NUM_ASCII_OFFSET;
384         
385         /* Verify the LRC */
386         if( strncmp( LRC, bitStream + i, charLen ) ) {
387                 fprintf( stderr, "ms_decode_bits(): Warning: LRC error decoding stream\n" );
388                 validSwipe = 1;
389         }
390
391         return validSwipe;
392 }
393
394 char _ms_decode_bits_char( char *bitStream, char *LRC, ms_dataType type ) {
395         int parity = 0, i;
396         char out;
397         int len; // char length not including parity
398         int offset; // offset to make it ASCII
399
400         if( type == ABA ) {
401                 len = ABA_CHAR_LEN - 1;
402                 offset = ABA_ASCII_OFFSET;
403         } else {
404                 len = IATA_CHAR_LEN - 1;
405                 offset = IATA_ASCII_OFFSET;
406         }
407
408         for( i = 0, out = 0; i < len; i++ ) {
409                 out |= ( bitStream[ i ] - NUM_ASCII_OFFSET ) << i; // using OR to assign the bits into the char
410                 if( bitStream[ i ] == '1' ) {
411                         LRC[ i ] = !LRC[ i ]; // flip the bit in the LRC for all 1 bits in the char
412                         parity++; // count the number of 1 bits for the parity bit
413                 }
414         }
415         out += offset;
416
417         if( ( parity & 1 ) == ( bitStream[ len ] - NUM_ASCII_OFFSET ) )
418                 out = BAD_CHAR; // return the error char if the calculated parity bit doesn't match the recorded one
419         
420         return out;
421 }
422
423
424 void ms_save( msData *ms, const char *filenamebase ) {
425         LList *trav;
426         FILE *output;
427         char filename[256];
428         int fnlen;
429
430         if( ms == NULL )
431                 return;
432
433         fnlen = strlen( filenamebase );
434         strncpy( filename, filenamebase, 256 );
435         
436         if( ms->peakList != NULL ) {
437                 strncpy( filename + fnlen, ".peaks", 256 - fnlen );
438
439                 output = fopen( filename, "w" );
440                 if( output == NULL )
441                         return;
442
443                 for( trav = ms->peakList->first; trav != NULL; trav = trav->next ) {
444                         fprintf( output, "%d %d\n", trav->idx, trav->amp );
445                 }
446
447                 fclose( output );
448         }
449
450         strncpy( filename + fnlen, ".pcm", 256 - fnlen );
451         output = fopen( filename, "w" );
452         if( output == NULL )
453                 return;
454
455         fwrite( ms->pcmData, sizeof( short ), ms->pcmDataLen, output );
456         
457         fclose( output );
458 }
459