source: projects/punch-card/driver/documation-m200/src/main.c @ 46

Last change on this file since 46 was 46, checked in by sven, 10 years ago

First import of the AVR Documenta M200 Punch Card Reader Controller. This project was started at 09.11.2009. Current status: Working (Beta status). Pending work: Cleaning up, find bug in circular buffer system, implementing a protocol (FTP/Hayes command set like).
Work was done on Windows 2000 with WinAVR and AVR Studio 4 (ISP programming).

File size: 14.1 KB
Line 
1/**
2 * AVR M200 Punch card reader controller
3 * Main file
4 *
5 * This file implements interrupt control, user I/O and the program flow.
6 * The card model is implemented by punchcard.{h, c}.
7 *
8 * The complete program is very specific to the wiring of the microcontroller,
9 * as defined in wiring.h. It was developed for an AVR ATmega 644 with a 8Mhz
10 * clock.
11 *
12 * The uC is set on an Olimex AVR-P40 board, having the TX pad connected to
13 * PD1 (pin15) and RX pad with PD0 (pin14).
14 *
15 * It was compiled with AVRStudio + WinAVR (gcc 4, avr-libc required).
16 *
17 * This file is part of the Punched Paper Project - Punch Card Device Drivers
18 * Copyright (C) 2009  Sven Koeppel
19 *
20 * This program is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU General Public License as
22 * published by the Free Software Foundation; either version 3 of
23 * the License, or (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, see
32 * <http://www.gnu.org/licenses/>.
33 **/
34
35#define __AVR_ATmega644__       1
36#define OSCSPEED        8000000         /* in Hz */
37
38#include <string.h>
39#include <stdio.h> // testweise
40
41#include "avr/io.h"
42#include "avr/interrupt.h"
43
44#include "punchcard.h"
45#include "wiring.h"
46
47char Text1[80];
48
49int uart_transmit(char c, FILE* stream);
50static FILE uart = FDEV_SETUP_STREAM(uart_transmit, NULL, _FDEV_SETUP_WRITE);
51
52/**
53 ** UART, I/O, LED
54 **/
55
56
57void Init(void)
58{
59        // Datenports einrichten
60
61    PORTA = 0x00; // erste 8 Daten-Input
62        PORTB = 0x00; // LED (auslassen, an=0x01), 3 Fehler (IN), Button (IN), ICSP
63        PORTC = 0x00; // 4 Daten, 3 Status (IN), 1 Signal (OUT)
64        PORTD = 0x00; // UART und -Flusssteuerung
65
66        DDRA = 0x00; // 8 Daten: Input
67        DDRB = (1 << DDB0); // Nur LED als Output, alles andere Input
68        DDRC = (1 << DDC6); // Nur Pick Command als Output, alles andere Input
69        DDRD = 0x00; // UART halt, IM jetzt auch
70
71        // Pin Change Intterupts aufsetzen
72        // PCMSK*: Pin Change Masks (welche Pins tragen zum Intterupt bei)
73        PCMSK1 = (1 << PCINT_ERROR) | (1 << PCINT_HCK) | (1 << PCINT_MOCK); // PORT B
74        PCMSK2 = (1 << PCINT_BSY) | (1 << PCINT_RDY);                     // PORT C
75        // Pin Change Interrupt Control Register: PC Interrupt Enable for Port B & C
76        PCICR = (1 << PCIE1) | (1 << PCIE2);
77
78        // Ausgezeichnete Interrupts aufsetzen (Index Mark IM haengt an INT0)
79        EICRA = (1 << ISC01) | (1 << ISC00); // rising edge von INT0 erzeugt intterupt
80        EIMSK = (1 << INT0); // interrupt fuer INT0 anschalten
81
82        // interrupt enable
83        sei();
84}
85
86void UartInit(uint32_t Baud)
87{
88        int BaudRate = OSCSPEED / (16 * Baud) - 1;
89
90        UBRR0H = (unsigned char) BaudRate>>8;
91        UBRR0L = (unsigned char) BaudRate;
92        //set BaudRate
93
94        UCSR0B = UCSR0B | (0b00011000); 
95        // RXEN & TXEN enable (Bits 4, 3 = 1)
96
97        UCSR0C = (UCSR0C | (0b10000110)); 
98        // USART Register Select (Bit 7 = 1)
99        // 8 data bits per frame (Bit 2, 1 = 1)
100
101        UCSR0C = UCSR0C & 0b11110111;
102        // 1 Stop bit (Bit 3 = 0)       
103}
104
105int uart_transmit(char c, FILE* stream) {
106        if(c == '\n')
107                uart_transmit('\r', stream);
108
109        while (!(UCSR0A & 0b00100000));
110        // PENDING: Hardware flow control
111        UDR0 = c;
112        return 0;
113}
114
115unsigned char UartReceive(void)
116{
117        if (UCSR0A & 0b10000000)
118        //if RXC(Bit 7) = 1
119                return UDR0;
120        else
121                return 0;
122}
123
124void UartTransmit(unsigned char Data)
125{
126        while (!(UCSR0A & 0b00100000));
127        //while UDRE = 0 --> ;
128        UDR0 = Data;
129}
130
131void LedMode (unsigned char Temp)
132{
133        switch (Temp)
134        {
135        // 1 - LED ON
136        case 1: PORTB = PORTB & 0&11111110;
137                PORTC = PORTC & 0&10111111;
138         break;
139        // 2 - Led OFF
140        case 2: PORTB = PORTB | 0b00000001;
141                PORTC = PORTC | 0b01000000;
142          break;
143        // 3 - Toggle Led
144        case 3: if (PINB & 0b00000001) PORTB = PORTB & 0b11111110;
145                        else    PORTB = PORTB | 0b00000001; break;
146        }
147}
148
149unsigned char Length(char Temp[20])
150{
151        unsigned char L=0;
152        while (Temp[L]) L++;
153        return L;
154}
155
156void Write(char Text[80])
157{
158        unsigned char Len, i, T;
159        Len = Length(Text);
160        //UartTransmit(Len);
161        for (i=0; i<Len; i++) 
162        {
163                T = Text[i];
164                UartTransmit(T);
165        }
166        strcpy(Text, "");
167}
168
169void WriteLn(char Text[80])
170{
171        unsigned char Len, i, T;
172        Len = Length(Text);
173        //UartTransmit(Len);
174        for (i=0; i<Len; i++) 
175        {
176                T = Text[i];
177                UartTransmit(T);
178        }
179        strcpy(Text, "");
180        UartTransmit(10);
181        UartTransmit(13);
182}
183
184void BlinkLed(void)
185{
186        unsigned int Br;
187        unsigned char State, End=0;
188        State = PINB;
189        WriteLn("");
190        strcpy(Text1, "Press any Key");
191        WriteLn(Text1);
192        while (End == 0)
193        {
194                End = UartReceive();
195                if ((End == 0) & (!(PINB & 0b00010000)))
196                {
197                        LedMode(3);
198                        for (Br = 20000; Br; Br--);
199                }               
200        }
201        PORTB = State; 
202}
203
204void print_bits(byte_t byte) {
205        char str[10];
206        byte_t bit; byte_t pos = 0;
207        for(bit = 7; bit >= 0; bit--) {
208                str[pos++] = ( (1 << bit) & byte ) ? '1' : '0';
209        }
210        str[8] = ' ';
211        str[9] = '\0';
212
213        strcat(Text1, str);
214}
215
216/**
217 ** Interrupt routine
218 **/
219
220static struct previous_pin_memory {
221        uint8_t pinc;
222        uint8_t pinb;
223} prev;
224
225static uint8_t user_start = 0; // muss noch sauber umgesetzt werden
226static uint8_t reader_waits_for_space = 0; // also defacto der WRITER
227
228ISR(PCINT1_vect) {
229        // Called for Pin changes on Error Signals:
230        // * PINB_ERR
231        // * PINB_HCK
232        // * PINB_MOCK
233
234        uint8_t pinb_jetzt = PINB;
235        uint8_t pin_changed = (pinb_jetzt ^ prev.pinb) & PCMSK1;
236        uint8_t rising_edge = ((((~prev.pinb) & pinb_jetzt) & PCMSK1) & pin_changed) == pin_changed ? 1 : 0;
237       
238        char* name = "???";
239        switch( pin_changed ) {
240                case (1 << PINB_ERROR):  name = "ERR"; break;
241                case (1 << PINB_HCK):  name = "HCK"; break;
242                case (1 << PINB_MOCK): name = "MOCK"; break;
243                case 0:
244                        printf("Too lazy, but not "); // und jetzt nicht breaken :-)
245                default:
246                        printf("Illegal PCINT1 raise: %x=>%x, %x, %x\n", prev.pinb, pinb_jetzt, pin_changed, rising_edge);
247                        prev.pinb = pinb_jetzt;
248                        return;
249        }
250
251        printf("%s %s\n", name, rising_edge ? "raising" : "falling");
252
253        prev.pinb = pinb_jetzt;
254}
255
256
257ISR(PCINT2_vect) {
258        // this routine is called for
259        //  * PINC_IM  : Index Mark (store current column)
260        //  * PINC_RDY : Ready (reader ready for new Pick Command)
261        //  * PINC_BSY : Busy (card edge - there is a card)
262        // to find out what changed, we make a backup of the former
263        // PINC at the end of this routine.
264
265        uint8_t pinc_jetzt = PINC;
266        uint8_t pin_changed = (pinc_jetzt ^ prev.pinc) & PCMSK2;
267        uint8_t rising_edge = check( pin_changed, (~prev.pinc) & pinc_jetzt );
268
269        switch( pin_changed ) {
270                case (1 << PCINT_RDY):
271                        // Ready is directly indicated by GREEN button on device.
272                        // Pick Command is only interpreted while Ready is up.
273                        if(rising_edge) {
274                                // reader got ready -- decide whether to start a new card,
275                                // if we hadn't started already
276                                if( check_pin(PINC, PINC_PC) ) {
277                                        // we have started already...
278                                        puts("READY rising, starting ASAP");
279                                } else {
280                                        // check if there's space in the buffer to start up
281                                        if(card_buffer_count_free() > 0) {
282                                                // Start.
283                                                // urhm... wait for user to start? user condition?
284                                                // yeah: quick & dirty:
285                                                if(user_start) {
286                                                        // start. BSY signal will create new card.
287                                                        start_reader();
288                                                }
289                                        }
290                                }
291                                puts("READY rising");
292                        } else {
293                                // device is no more ready -- perhaps user shutdown (by button).
294                                puts("READY falling");
295                        }
296                        break;
297                case (1 << PCINT_BSY):
298                        // busy =~= card edge
299                        if(rising_edge) {
300                                if(current_write_card.offset != CARD_EMPTY) {
301                                        // start a new card
302                                        if(card_buffer_write_advance() != SUCCESS) {
303                                                // No more space in buffer! VERY BAD!
304                                                puts("BUSY rising, LOOSING DATA!");
305                                        } else
306                                                printf("BUSY rising, new card %d (reader: %d)\n",
307                                                        card_buffer.write_offset, card_buffer.read_offset);
308                                } else {
309                                        puts("BUSY rising, staying card");
310                                }
311                        } else {
312                                puts("BSY falling");
313
314                                // nochmal sicherheitshalber, wobei das sowieso viel zu spaet ist
315                                if( !card_buffer_count_free() ) {
316                                        stop_reader();
317                                }
318                        }
319                        break;
320
321                case 0:
322                        // Signal lag zu kurz an
323                        printf("Lost Interrupt, state %x ed=%x\n", pinc_jetzt, rising_edge);
324                        break;
325                default:
326                        // illegal intterupt!
327                        printf("Illegal interrupt! PINC was %x is %x changed %x flanke %x\n",
328                                prev.pinc, pinc_jetzt, pin_changed, rising_edge);
329                        break;
330        }
331
332        // backup new "old" value
333        prev.pinc = pinc_jetzt;
334} // ISR
335
336ISR(INT0_vect) {
337        // soho... willkommen zum neuen IM-Interrupt :-)
338        // hier koennen wir sicher sein, dass gerade eine IM-Flanke auftrat.
339        // die wird ab 50ns gemessen :-)
340        // die 5 Zyklen bis zur verarbeitung spielen dann eh keine Rolle mehr
341
342        if( ! (PINC & (1 << PINC_BSY)) ) {
343                // die kann man verwerfen, keine Kartenkante
344                puts("IMS");
345                return;
346        }
347
348        if(current_write_card.offset < 0 || current_write_card.offset >= CARD_LEN ) {
349                puts("BAD card! Stopping reader");
350                if(PINC & (1 << PORTC_PC)) {
351                        puts("Reader wasnt stopped");
352                }
353                stop_reader();
354                return;
355        }
356
357        // oder radikal so (ist ja genug Zeit zum Abchecken da)
358        if( !card_buffer_count_free() )
359                stop_reader();
360
361        // store column
362        current_write_column =
363                (check_pin(PINA, PINA_D0) << COL0) |  // copy register A
364                (check_pin(PINA, PINA_D1) << COL1) |  // (bitwise since we don't want to
365                (check_pin(PINA, PINA_D2) << COL2) |  // make assumptions about bit locations)
366                (check_pin(PINA, PINA_D3) << COL3) |
367                (check_pin(PINA, PINA_D4) << COL4) |
368                (check_pin(PINA, PINA_D5) << COL5) |
369                (check_pin(PINA, PINA_D6) << COL6) |
370                (check_pin(PINA, PINA_D7) << COL7) |
371
372                (check_pin(PINC, PINC_D8) << COL8) |
373                (check_pin(PINC, PINC_D9) << COL9) |
374                (check_pin(PINC, PINC_D11) << COL11) |
375                (check_pin(PINC, PINC_D12) << COL12);
376
377        // column stored. increase column counter
378        // (correctness will be checked on next call)
379        current_write_card.offset++;
380
381        // Das war die 80. Spalte (intern 79) => finalisieren.
382        if(current_write_card.offset == CARD_LEN) {
383                // diese karte ist fertig
384                // finalize the current card
385                //current_write_card.offset = CARD_READY; // unnoetig, da CARD_READY == CARD_LEN
386                puts("wr++");
387
388                // try to create a new card
389                if(card_buffer_write_advance() != SUCCESS) {
390                        // no more space! turn off Punch Instruction!
391                        stop_reader();
392                        puts("No more space on buffer.");
393                        reader_waits_for_space = 1;
394                }
395        }
396
397
398
399        // und Blinken darf er auch gerne :-)
400        if (PINB & 0b00000001)
401                start_led();
402        else
403                stop_led();
404}
405
406
407
408int main()
409{
410        card_buffer_flush();
411        Init();
412        UartInit(38400);
413        LedMode(1);
414
415        // nette sachen machen koennen
416        stdout = &uart;
417
418        unsigned char Action = 0, display_menu;
419        enum format {
420                HEX = 4,
421                DEBUG = 5,
422                BINARY = 6
423        } out_format = DEBUG;
424        while (1)
425        {
426                Action = 0;
427                display_menu = 0;
428                //out_format = 4;
429                puts("");
430                puts("Menu");
431                puts(" 1) Start reading");
432                puts(" 2) Stop reading");
433                puts(" 3) Stop; Reset buffer");
434                puts(" 4) HEX  5) DEBUG  6) BINARY JONES");
435                puts("");
436                puts("Choose Action: ");
437
438                while (! display_menu)
439                {
440                        // erst mal buffer abarbeiten
441                        if( current_read_card.offset == CARD_READY ) {
442                                int col;
443
444                                printf("Karte in rd %d rw %d, cols rd %d rw %d\n", card_buffer.read_offset, card_buffer.write_offset,
445                                        current_read_card.offset, current_write_card.offset);
446
447                                // Karte abgearbeitet
448                                current_read_card.offset = CARD_DONE;
449
450                                //break; // Karte NICHT komplett ausgeben. Hier stoppen.
451
452                               
453                                if(out_format != BINARY) {
454                                        for(col = 0; col < CARD_LEN; col++) {
455                                                if(out_format == HEX) {
456                                                        printf("%x,%x ", (uint8_t) (current_read_card.columns[col] >> 8),
457                                                                (uint8_t) (current_read_card.columns[col]));
458                                                } else if(out_format == DEBUG) {
459                                                        printf("%02d: ", col+1);
460                                                        column_print( &current_read_card.columns[col] );
461                                                } else {
462                                                        puts("Bad output format");
463                                                        break;
464                                                }
465                                        }
466                                        puts("");
467                                } else { // binary
468                                        puts("<CARD>");
469                                        // make two columns to three bytes, after Douglas Jones
470                                        uint8_t x = 0;
471                                        Column even_col, odd_col;
472                                        while(x <= CARD_LEN) {
473                                                even_col = current_read_card.columns[x++];
474                                                odd_col = current_read_card.columns[x++];
475
476                                                putchar( even_col >> 4 ); // erstes byte
477                                                putchar( ((even_col & 017) << 4) | (odd_col >> 8) ); // zweites byte
478                                                putchar( odd_col & 00377 ); // drittes byte
479                                        }
480                                        puts("</CARD>");
481                                }
482                        }
483
484                        if( current_read_card.offset == CARD_DONE) {
485                                // alle karten abgearbeitet, versuche zur naechsten
486                                // Karte zu kommen
487                                if( card_buffer_read_advance() != SUCCESS) {
488                                        puts("output waiting for next");
489                                } else {
490                                        puts("cr+");
491                                }
492
493                                // und der Writer kann jetzt auch wieder loslegen
494                                // also eigentlich wartet hier ja der WRITER
495                                if(reader_waits_for_space) {
496                                        // leser hat auf uns gewartet (puffer war voll, leser war angehalten,
497                                        // wir haben nun eine weitere Karte gelesen => Leser kann in dieses
498                                        // Feld nun wieder schreiben)
499                                        if(card_buffer_write_advance() == SUCCESS) {
500                                                // es kann wieder weitergehen fuer den Leser
501                                                reader_waits_for_space = 0;
502                                                start_reader();
503                                        } else {
504                                                puts("Deadline, writer waits for reader");
505                                        }
506                                }
507
508                        }
509
510
511                        // dann nutzereingaben abarbeiten
512                        Action = UartReceive();
513                        if (Action)     Action = Action - 48;
514                        if (Action)
515                        {
516                                display_menu = 1;
517                                switch(Action) {
518                                        case 1:
519                                                user_start = 1;
520                                                start_reader();
521                                                start_led();
522                                                break;
523                                        case 2:
524                                                user_start = 0;
525                                                stop_reader();
526                                                stop_led();
527                                                break;
528                                        case 3:
529                                                puts("Soft Reset");
530                                                user_start = 0;
531                                                stop_reader();
532                                                stop_led();
533                                                card_buffer_flush();
534                                                break;
535                                        case 4:
536                                        case 5:
537                                        case 6:
538                                                out_format = Action;
539                                                printf("Setting out format to %d\n", out_format);
540                                                break;
541                                        default:
542                                                printf("Illegal input %d\n", Action);
543                                }
544                        } // if action
545                }
546        }
547        return 0;
548}
Note: See TracBrowser for help on using the repository browser.
© 2008 - 2013 technikum29 • Sven Köppel • Some rights reserved
Powered by Trac
Expect where otherwise noted, content on this site is licensed under a Creative Commons 3.0 License