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

Last change on this file since 50 was 50, checked in by sven, 10 years ago
  • The PC Documation M200 uC Serial Communication Protocol: Initial write
  • driver/documation-m200: Implemented the protocol (code compiles, but not tested yet on device)

-- Sven @ p3

File size: 8.8 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#include "io.h"
47
48char Text1[80];
49
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
86
87void UartInit(uint32_t Baud)
88{
89        int BaudRate = OSCSPEED / (16 * Baud) - 1;
90
91        UBRR0H = (unsigned char) BaudRate>>8;
92        UBRR0L = (unsigned char) BaudRate;
93        //set BaudRate
94
95        UCSR0B = UCSR0B | (0b00011000);
96        // RXEN & TXEN enable (Bits 4, 3 = 1)
97
98        UCSR0C = (UCSR0C | (0b10000110));
99        // USART Register Select (Bit 7 = 1)
100        // 8 data bits per frame (Bit 2, 1 = 1)
101
102        UCSR0C = UCSR0C & 0b11110111;
103        // 1 Stop bit (Bit 3 = 0)     
104}
105
106
107/**
108 ** Interrupt routine
109 **/
110
111
112ISR(PCINT1_vect) {
113        // Called for Pin changes on Error Signals:
114        // * PINB_ERR
115        // * PINB_HCK
116        // * PINB_MOCK
117
118        uint8_t pinb_jetzt = PINB;
119        uint8_t pin_changed = (pinb_jetzt ^ status.prev_pinb) & PCMSK1;
120        uint8_t rising_edge = ((((~status.prev_pinb) & pinb_jetzt) & PCMSK1) & pin_changed) == pin_changed ? 1 : 0;
121       
122        char* name = "???";
123        switch( pin_changed ) {
124                case (1 << PINB_ERROR):  name = "ERR"; break;
125                case (1 << PINB_HCK):  name = "HCK"; break;
126                case (1 << PINB_MOCK): name = "MOCK"; break;
127                case 0:
128                        printf("Too lazy, but not "); // und jetzt nicht breaken :-)
129                default:
130                        printf("Illegal PCINT1 raise: %x=>%x, %x, %x\n", status.prev_pinb, pinb_jetzt, pin_changed, rising_edge);
131                        status.prev_pinb = pinb_jetzt;
132                        return;
133        }
134
135        printf("%s %s\n", name, rising_edge ? "raising" : "falling");
136
137        status.prev_pinb = pinb_jetzt;
138}
139
140
141ISR(PCINT2_vect) {
142        // this routine is called for
143        //  * PINC_IM  : Index Mark (store current column)
144        //  * PINC_RDY : Ready (reader ready for new Pick Command)
145        //  * PINC_BSY : Busy (card edge - there is a card)
146        // to find out what changed, we make a backup of the former
147        // PINC at the end of this routine.
148
149        uint8_t pinc_jetzt = PINC;
150        uint8_t pin_changed = (pinc_jetzt ^ status.prev_pinc) & PCMSK2;
151        uint8_t rising_edge = check( pin_changed, (~status.prev_pinc) & pinc_jetzt );
152
153        switch( pin_changed ) {
154                case (1 << PCINT_RDY):
155                        // Ready is directly indicated by GREEN button on device.
156                        // Pick Command is only interpreted while Ready is up.
157                        if(rising_edge) {
158                                // reader got ready -- decide whether to start a new card,
159                                // if we hadn't started already
160                                if( check_pin(PINC, PINC_PC) ) {
161                                        // we have started already...
162                                        puts("READY rising, starting ASAP");
163                                } else {
164                                        // check if there's space in the buffer to start up
165                                        if(card_buffer_count_free() > 0) {
166                                                // Start.
167                                                // urhm... wait for user to start? user condition?
168                                                // yeah: quick & dirty:
169                                                if(status.user_instruction == START_READER) {
170                                                        // start. BSY signal will create new card.
171                                                        start_reader();
172                                                }
173                                        }
174                                }
175                                puts("READY rising");
176                        } else {
177                                // device is no more ready -- perhaps user shutdown (by button).
178                                puts("READY falling");
179                        }
180                        break;
181                case (1 << PCINT_BSY):
182                        // busy =~= card edge
183                        if(rising_edge) {
184                                if(current_write_card.offset != CARD_EMPTY) {
185                                        // start a new card
186                                        if(card_buffer_write_advance() != SUCCESS) {
187                                                // No more space in buffer! VERY BAD!
188                                                puts("BUSY rising, LOOSING DATA!");
189                                        } else
190                                                printf("BUSY rising, new card %d (reader: %d)\n",
191                                                        card_buffer.write_offset, card_buffer.read_offset);
192                                } else {
193                                        puts("BUSY rising, staying card");
194                                }
195                        } else {
196                                puts("BSY falling");
197
198                                // nochmal sicherheitshalber, wobei das sowieso viel zu spaet ist
199                                if( !card_buffer_count_free() ) {
200                                        stop_reader();
201                                }
202                        }
203                        break;
204
205                case 0:
206                        // Signal lag zu kurz an
207                        printf("Lost Interrupt, state %x ed=%x\n", pinc_jetzt, rising_edge);
208                        break;
209                default:
210                        // illegal intterupt!
211                        printf("Illegal interrupt! PINC was %x is %x changed %x flanke %x\n",
212                                status.prev_pinc, pinc_jetzt, pin_changed, rising_edge);
213                        break;
214        }
215
216        // backup new "old" value
217        status.prev_pinc = pinc_jetzt;
218} // ISR
219
220ISR(INT0_vect) {
221        // soho... willkommen zum neuen IM-Interrupt :-)
222        // hier koennen wir sicher sein, dass gerade eine IM-Flanke auftrat.
223        // die wird ab 50ns gemessen :-)
224        // die 5 Zyklen bis zur verarbeitung spielen dann eh keine Rolle mehr
225
226        if( ! (PINC & (1 << PINC_BSY)) ) {
227                // die kann man verwerfen, keine Kartenkante
228                puts("IMS");
229                return;
230        }
231
232        if(current_write_card.offset < 0 || current_write_card.offset >= CARD_LEN ) {
233                puts("BAD card! Stopping reader");
234                if(PINC & (1 << PORTC_PC)) {
235                        puts("Reader wasnt stopped");
236                }
237                stop_reader();
238                return;
239        }
240
241        // oder radikal so (ist ja genug Zeit zum Abchecken da)
242        if( !card_buffer_count_free() )
243                stop_reader();
244
245        // store column
246        current_write_column =
247                (check_pin(PINA, PINA_D0) << COL0) |  // copy register A
248                (check_pin(PINA, PINA_D1) << COL1) |  // (bitwise since we don't want to
249                (check_pin(PINA, PINA_D2) << COL2) |  // make assumptions about bit locations)
250                (check_pin(PINA, PINA_D3) << COL3) |
251                (check_pin(PINA, PINA_D4) << COL4) |
252                (check_pin(PINA, PINA_D5) << COL5) |
253                (check_pin(PINA, PINA_D6) << COL6) |
254                (check_pin(PINA, PINA_D7) << COL7) |
255
256                (check_pin(PINC, PINC_D8) << COL8) |
257                (check_pin(PINC, PINC_D9) << COL9) |
258                (check_pin(PINC, PINC_D11) << COL11) |
259                (check_pin(PINC, PINC_D12) << COL12);
260
261        // column stored. increase column counter
262        // (correctness will be checked on next call)
263        current_write_card.offset++;
264
265        // Das war die 80. Spalte (intern 79) => finalisieren.
266        if(current_write_card.offset == CARD_LEN) {
267                // diese karte ist fertig
268                // finalize the current card
269                //current_write_card.offset = CARD_READY; // unnoetig, da CARD_READY == CARD_LEN
270                puts("wr++");
271
272                // try to create a new card
273                if(card_buffer_write_advance() != SUCCESS) {
274                        // no more space! turn off Punch Instruction!
275                        stop_reader();
276                        puts("No more space on buffer.");
277                        status.reader_waits_for_space = 1;
278                }
279        }
280
281
282
283        // und Blinken darf er auch gerne :-)
284        if (PINB & 0b00000001)
285                start_led();
286        else
287                stop_led();
288}
289
290
291
292int main()
293{
294        card_buffer_flush();
295        Init();
296        UartInit(38400);
297        start_led();
298
299        // nette sachen machen koennen
300        stdout = &uart;
301
302        user_input_loop();
303        return 0;
304}
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