source: projects/bull-anelex-project/trunk/anelex-interface/src/frontend.c @ 63

Last change on this file since 63 was 63, checked in by sven, 9 years ago

Anelex-Interface: Finalized the Builtin memory text printing (which actually was a lot of work...).

File size: 8.7 KB
Line 
1/**
2 * ANELEX PRINTER Interface Microcontroller
3 * RS232 client interaction
4 *
5 * This file collects all routines that directly communicate
6 * to the computer/PC/user/terminal/other uc/anything that is
7 * wired via the RS232 port.
8 *
9 * This file is part of the Bull Anelex Project
10 * Copyright (C) 2010, 2011 Sven Köppel, technikum29.de
11 *
12 * This program is free software; you can redistribute
13 * it and/or modify it under the terms of the GNU General
14 * Public License as published by the Free Software
15 * Foundation; either version 3 of the License, or (at
16 * your option) any later version.
17 *
18 * This program is distributed in the hope that it will
19 * be useful, but WITHOUT ANY WARRANTY; without even the
20 * implied warranty of MERCHANTABILITY or FITNESS FOR A
21 * PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
23 *
24 * You should have received a copy of the GNU General
25 * Public License along with this program; if not, see
26 * <http://www.gnu.org/licenses/>.
27 *
28 **/
29
30#include "frontend.h"
31#include "anelex.h"
32#include "data.h"
33
34// weil wir kein math.h haben...
35#define min(a,b) ((a)<(b) ? (a) : (b))
36
37/**
38 * The USART recieve interrupt vector.
39 * This function is the write_advance for the pbuf input ring buffer.
40 * TODO: Not ISR but make INTERRUPTABLE! (selbst unterbrechbar!)
41 **/
42ISR(USART0_RX_vect) {
43        char c = UDR0;
44        // verbose debugging with states:
45        //printf("read %x, r=%d, w=%d, used=%d, loss=%d, dirt=%d, nl=%d, cts=%s\n",
46        //      c, pbuf.read_offset, pbuf.write_offset, pbuf.used_elements, pbuf.data_loss, pbuf.dirty_write, pbuf.line_counter, is_cts()?"on":"off");
47
48        if(c == '\r') {
49                switch(input_line_end) {
50                        case CRNL:
51                                // Windows default \r\n: Ignore CR, only obey NL
52                                return;
53                        case CR:
54                                // \r only as line end: just convert to ordinary unix style \n
55                                c = '\n';
56                        case NL:
57                                // just NL which is our standard mode.
58                                break;
59                } // switch
60        } // if CR
61
62        if(!is_cts()) pbuf.dirty_write++; // just for debugging
63
64        int8_t new_offset = (pbuf.write_offset + 1) % BUFFER_LEN;
65
66        if(new_offset == pbuf.read_offset) {
67                // no more space!
68                pbuf.data_loss++;
69                // wipe current data! Data Loss!
70                putchar('@');
71        } else {
72                // still space left
73                pbuf.buffer[new_offset] = c;
74                pbuf.write_offset = new_offset;
75                pbuf.used_elements++;
76                if(c == '\n') {
77                  pbuf.line_counter++;
78        }
79                putchar(c); // vorsicht bei Newlines - hier beabsichtigt (NL->NLCR)
80        }
81
82        // when space is running out then make PC stop sending.
83        if(pbuf.used_elements > BUFFER_LEN - 10)
84                stop_cts();
85
86        // line_state, number of lines, etc. is checked in readline()!
87}
88
89/**
90 * builtin_readline: Does the work when the builtin reading system
91 * is active. Function is called by readline().
92 **/
93void builtin_readline() {
94        // read text from builtin memory (data.c).
95        //printf("Builtin system runnig, index=%d, roffset=%d\n", builtin_data.index, builtin_data.read_offset);
96        // just a shorthand:
97        PGM_P string = builtin_strings[builtin_data.index - 1];
98        // search next newline char (returns NULL if not found):
99        PGM_P nlpos = strchr_P(string + builtin_data.read_offset, '\n');
100        if(nlpos == NULL) {
101                //puts("Reached end of string! (No more newline)");
102                builtin_data.index = 0;
103                builtin_data.read_offset = 0;
104                return;
105        }
106
107        uint8_t nloffset = min(nlpos - string - builtin_data.read_offset, LINE_LENGTH);
108        //printf("Detected NL at offset %d. Currrent Line:\n", nloffset);
109        strncpy_P(current_line, string + builtin_data.read_offset, nloffset);
110        // RS232 feedback: Print text out (like readline() gives feedback)
111        puts(current_line);
112
113        builtin_data.read_offset += nloffset + 1; // one behind the newline
114        // important: read offset counts from 0, strlen from 1.
115        if(builtin_data.read_offset + 1 >= strlen_P(string)) {
116                //puts("Reached end of string!");
117                builtin_data.index = 0;
118                builtin_data.read_offset = 0;
119        }
120}
121
122/**
123 * The readline function reads one line from RS232 and puts it into the driver
124 * output text buffer current_line[] (anelex.h). The real work is done asynchronously
125 * by the USART RX ISR. Alternatively the next line from the builtin program memory text
126 * is copied to current_line[] by builtin_readline().
127 *
128 * This function is called by main().
129 **/
130void readline() {
131        memset(&current_line, 0, LINE_LENGTH); // null the output buffer (important)
132
133        printf("Readline!\n");
134        // check if we get the text from ROM
135        if(builtin_data.index) {
136                builtin_readline();
137                return;
138        }
139
140        start_cts();          // let PC start sending! (important)
141        pbuf.data_loss = 0;   // reset statistics for
142        pbuf.dirty_write = 0; // new readline run.
143
144        // loop for first user input
145        for(;;) {
146                if(line_state == LINE_FINISHED && pbuf.line_counter) {
147                        // printer finished printing and is ready for new data.
148                        // and we have detected a full line in the buffer
149                        //_delay_ms(2000); // zum manuellen testen: schnell viele zeilen eingeben
150                        stop_cts();
151                        break;
152                } else if(is_button()) {
153                        // button pressed down - wait until raised again
154                        stop_cts();
155                        while(is_button());
156                        puts("Button pressed.");
157                        strcpy(current_line, "?print 1");
158                        return; // important: Quit readline now.
159                } else if(!is_cts()) {
160                        // apperantly the buffer is full and the ISR made a full stop.
161                        // Hence we must use current contents as a line (remark that the
162                        // line is not finished!). Since the buffer should be large, the
163                        // line is longer than the printer can print, anyway.
164                        puts("ctsoff");
165                        break;
166                }
167        }
168
169        // now copy one line from the buffer to the current_line
170        // output buffer for the anelex driver (which is already filled with 0x00)
171        for(int i=0; i < LINE_LENGTH; i++) {
172                // read advance:
173                pbuf.read_offset = (pbuf.read_offset + 1) % BUFFER_LEN;
174
175                char c = pbuf.buffer[pbuf.read_offset];
176                pbuf.buffer[pbuf.read_offset] = '\0';
177                pbuf.used_elements--;
178                if(c == '\n') {
179                        // end of line detected
180                        pbuf.line_counter--;
181                        break;
182                } else
183                        // store char to anelex driver buffer
184                        current_line[i] = c;
185               
186                if(!pbuf.used_elements)
187                        // buffer is absolutely empty
188                        break;
189        } // for
190
191        // checkout some statistics
192        if(pbuf.data_loss) {
193                printf("Lost %d chars!\n", pbuf.data_loss);
194        }
195
196} // readline()
197
198
199/**
200 * Parses the current_line[] and executes a command. Expects current_line[] to be
201 * a command, which is checked in the main() loop.
202 * Function is called by main().
203 **/
204void exec_command() {
205        char* command = current_line + 1; // strip leading '?'
206        printf("Executing command %s\n", command);
207
208        if(strcasecmp(command, "help") == 0) {
209                builtin_print_help();
210        } else if(memcmp(command, "list", 4) == 0) { // 4 = strlen("list")
211                int i = atoi(command + 4); // returns 0 on error
212                if(i <= 0 || i > builtin_strings_length) {
213                        printf("! Usage: ?list ID with ID between 0 and %d\n", builtin_strings_length);
214                        builtin_print_list();
215                } else {
216                        // just print out text on terminal
217                        puts_P(builtin_strings[i-1]);
218                }
219        } else if(memcmp(command, "print", 5) == 0) { // 5 = strlen("print")
220                int i = atoi(command + 5);
221                if(i <= 0 || i > builtin_strings_length) {
222                        printf("! Same syntax like ?list, just prints out to the ANELEX.\n"
223                                "! Make sure you tested before on terminal, e.g ?list 5 => ?print 5\n");
224                } else {
225                        // print out text on ANELEX. That is:
226                        printf("! Now printing text no. %d on ANELEX printer\n", i);
227                        builtin_data.index = i;
228                        return; // read new line, all work is done in readline()
229                }
230        } else if(strcasecmp(command, "ping") == 0) {
231                puts("Pong :-)");
232        } else {
233                puts("! Command not understood. Please type ?help");
234        }
235} // exec_command
236
237/**
238 * USART TX function for avr-libc stdio.h toolchain. This function
239 * prints out exactly one character and converts on the fly NL to
240 * CR NL. See uart_transmit() for the function without conversion.
241 **/
242int stdout_transmit(char c, FILE *stream) {
243        if (c == '\n')
244                stdout_transmit('\r', stream);
245        uart_transmit(c);
246        return 0;
247}
248
249/**
250 * UART initialisation, called at main() start. In this program we also
251 * set up the RX interrupt enable flag.
252 **/
253void uart_init(uint32_t Baud) {
254    int BaudRate = F_CPU / (16 * Baud) - 1;
255
256    UBRR0H = (unsigned char) BaudRate>>8;
257    UBRR0L = (unsigned char) BaudRate;
258    //set BaudRate
259
260    UCSR0B = UCSR0B | (0b00011000);
261    // RXEN & TXEN enable (Bits 4, 3 = 1)
262
263    UCSR0C = (UCSR0C | (0b10000110));
264    // USART Register Select (Bit 7 = 1)
265    // 8 data bits per frame (Bit 2, 1 = 1)
266
267    UCSR0C = UCSR0C & 0b11110111;
268    // 1 Stop bit (Bit 3 = 0)
269
270        UCSR0B = UCSR0B | (1 << RXCIE0);
271        // Enable Recieve Interrupt (Print Buffer)
272}
273
274/**
275 * Helper function to print out a byte as binary representation to STDOUT.
276 **/
277void print_bits(byte_t byte) {
278        char str[10];
279        puts(itoa(byte, str, 2));
280}
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