OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [io/] [usb/] [serial/] [slave/] [current/] [tests/] [usb2serial.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      usb2serial.c
4
//
5
//      Example application for the USB serial layer in eCos.
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 2008, 2010 Free Software Foundation, Inc.                        
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//===========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):    Frank M. Pagliughi (fmp), SoRo Systems, Inc.
43
// Contributors: 
44
// Date:         2008-06-02
45
// Description:  USB serial example application.
46
//
47
//####DESCRIPTIONEND####
48
//===========================================================================
49
 
50
#include <cyg/kernel/kapi.h>
51
#include <cyg/hal/hal_arch.h>
52
#include <cyg/infra/diag.h>
53
#include <pkgconf/kernel.h>
54
#include <cyg/io/serialio.h>
55
 
56
#include <cyg/io/usb/usbs_serial.h>
57
#include <pkgconf/io_usb_slave_serial.h>
58
 
59
#include <stdio.h>
60
#include <stdlib.h>
61
#include <unistd.h>
62
#include <fcntl.h>
63
#include <sys/stat.h>
64
 
65
// This application creates a USB-serial converter. To the host it will appear
66
// as a single serial USB port, such as /dev/ttyUSB0 for a Linux host.
67
// Any characters received from the USB host will be sent out the serial port
68
// and visa-verse. It creates a separate, dedicated thread for each direction.
69
// 
70
// It uses the eCos USB-serial layer to enumerate with the USB host and monitor
71
// the connection, but then uses standard C I/O functions to perform the 
72
// communications.
73
// 
74
// The USB serial module can be configured as a generic adapter or an an ACM
75
// communications class device. For the latter, the application handles the
76
// USB communications class requests which allows it to receive requests from
77
// the host to set serial parameters, like the baud rate. This actually turns
78
// this example into a more realistic USB-serial adapter that can be configured
79
// dynamically by the host.
80
// 
81
// The eCos library must be configured with the packages for USB slave, USB 
82
// serial, and File I/O. It also requires the proper serial port driver for the
83
// target platform.
84
// 
85
// This example was tested with the AT91SAM7S-EK board, but should work with any
86
// board that has a USB slave and serial port, and the necessary drivers.
87
 
88
 
89
// Comment this line out to remove debug output.
90
#define DEBUG_OUTPUT
91
 
92
#if defined(DEBUG_OUTPUT)
93
#define DBG diag_printf
94
#else
95
#define DBG (1) ? (void)0 : diag_printf
96
#endif
97
 
98
// Set these to the USB devtab entries for the Tx and Rx Bulk endpoints 
99
// selected in the configuration of the USB serial subsystem.
100
#define USB_TX_DEV  "/dev/usbs1"
101
#define USB_RX_DEV  "/dev/usbs2"
102
 
103
// Set this for any available serial port on the target.
104
#define SER_DEV     "/dev/ser0"
105
 
106
// Buffer for incoming USB bulk data. The local USB driver can probably split
107
// packets, but just in case, making this the page size of the host might be
108
// helpful.
109
#define BUF_SIZE 4096
110
static char usb2ser_buf[BUF_SIZE];
111
 
112
// The threads
113
cyg_thread thread[2];
114
 
115
// Space for two 4K stacks
116
#define THREAD_STACK_SIZE 4096
117
char stack[2][THREAD_STACK_SIZE];
118
 
119
// The handles for the threads
120
cyg_handle_t    usb2ser_thread,
121
                ser2usb_thread;
122
 
123
// --------------------------------------------------------------------------
124
// For an ACM serial device we can handle the USB class messages to deal with
125
// requests from the host like setting the serial parameters (baud rate, 
126
// etc).
127
 
128
#ifdef CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM
129
 
130
static cyg_uint8    acm_buf[32];
131
static cyg_uint32   baud = 34800;
132
 
133
// --------------------------------------------------------------------------
134
// Handler for the completion of a SetLineCoding request from the host.
135
// The 'acm_buf' should contain the 7-byte request OUT packet from the
136
// host. This contains a request to change the serial parameters.
137
// In this example function, we will accept a few different baud rates.
138
// To keep the example relatively simple, though, we keep the other serial
139
// parameters to 1 stop bit, no parity, 8 data bits.
140
 
141
static usbs_control_return
142
acm_set_line_coding(usbs_control_endpoint* ep0, int n)
143
{
144
  int err;
145
  cyg_uint32 req_baud;
146
  cyg_io_handle_t handle;
147
 
148
  // Get the requested baud rate from the received ctrl OUT packet
149
  req_baud = ((acm_buf[3] << 24) | (acm_buf[2] << 16) |
150
              (acm_buf[1] << 8) | acm_buf[0]);
151
 
152
  DBG("Set Baud: %u\n", (unsigned) baud);
153
 
154
  // Look up the serial handle and attempt to set the baud rate.
155
  if (cyg_io_lookup(SER_DEV, &handle) == 0) {
156
    cyg_serial_info_t ser_info;
157
    cyg_uint32 len = sizeof(ser_info);
158
 
159
    switch (baud) {
160
      case   9600 : ser_info.baud = CYGNUM_SERIAL_BAUD_9600;      break;
161
      case  38400 : ser_info.baud = CYGNUM_SERIAL_BAUD_38400;     break;
162
      case 115200 : ser_info.baud = CYGNUM_SERIAL_BAUD_115200;    break;
163
      default:
164
        DBG("Unsupported baud rate\n");
165
        return USBS_CONTROL_RETURN_HANDLED;
166
    }
167
    ser_info.stop = CYGNUM_SERIAL_STOP_1;
168
    ser_info.parity = CYGNUM_SERIAL_PARITY_NONE;
169
    ser_info.word_length = CYGNUM_SERIAL_WORD_LENGTH_8;
170
    ser_info.flags = 0;
171
 
172
    err = cyg_io_set_config(handle, CYG_IO_SET_CONFIG_SERIAL_INFO,
173
                            &ser_info, &len);
174
    if (err == 0)
175
      baud = req_baud;
176
    else {
177
      DBG("Error setting serial params\n");
178
    }
179
  }
180
  else {
181
    DBG("Error looking up serial device: %s\n", SER_DEV);
182
  }
183
  return USBS_CONTROL_RETURN_HANDLED;
184
}
185
 
186
// --------------------------------------------------------------------------
187
// Handler for the ACM class messages.
188
// 
189
static usbs_control_return
190
acm_class_handler(usbs_control_endpoint* ep0, void* data)
191
{
192
  usbs_control_return result = USBS_CONTROL_RETURN_UNKNOWN;
193
 
194
  usb_devreq  *req = (usb_devreq *) ep0->control_buffer;
195
 
196
  static cyg_uint8 rsp_buf[32];
197
 
198
  DBG("ACM Class Handler\n");
199
 
200
  switch (req->request) {
201
 
202
    case USBS_SERIAL_SET_LINE_CODING :
203
      DBG("Set Line Coding\n");
204
      memset(acm_buf, 0, 32);
205
      ep0->buffer = acm_buf;
206
      ep0->buffer_size = 7;
207
      ep0->complete_fn = acm_set_line_coding;
208
      result = USBS_CONTROL_RETURN_HANDLED;
209
      break;
210
 
211
    case USBS_SERIAL_GET_LINE_CODING :
212
      DBG("Get Line Coding\n");
213
      rsp_buf[0] = baud & 0xFF;
214
      rsp_buf[1] = (baud >>  8) & 0xFF;
215
      rsp_buf[2] = (baud >> 16) & 0xFF;
216
      rsp_buf[3] = (baud >> 24) & 0xFF;
217
      rsp_buf[4] = 0; // One stop bit
218
      rsp_buf[5] = 0; // No parity
219
      rsp_buf[6] = 8; // 8 data bits
220
      ep0->buffer = rsp_buf;
221
      ep0->buffer_size = 7;
222
      result = USBS_CONTROL_RETURN_HANDLED;
223
      break;
224
 
225
    default :
226
      DBG("*** Unhandled ACM Request: 0x%02X ***\n",
227
          (unsigned) req->request);
228
  }
229
 
230
  return result;
231
}
232
 
233
#endif      // CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM
234
 
235
// --------------------------------------------------------------------------
236
// Thread receives packets from the USB and sends them out the serial port
237
// It uses a buffered stdio input, an un-buffered low-level file output.
238
// This isn't terribly efficient, but rather an example of both methods.
239
 
240
void usb2ser_func(cyg_addrword_t data)
241
{
242
  int  c;
243
  FILE *rxf = fopen(USB_RX_DEV, "r");
244
  int   txh = open(SER_DEV, O_WRONLY, 0);
245
 
246
  DBG("Usb2Ser: Thread starting\n");
247
 
248
  if (!rxf) {
249
    DBG("Error opening USB rx port\n");
250
    return;
251
  }
252
 
253
  if (txh < 0) {
254
    DBG("Error opening serial tx port\n");
255
    return;
256
  }
257
 
258
  // Give the USB receiver an adequate buffer.
259
  setvbuf(rxf, usb2ser_buf, _IOFBF, BUF_SIZE);
260
 
261
  while (1) {
262
 
263
    // ----- Wait for the host to configure -----
264
 
265
    DBG("Usb2Ser: Waiting for USB configuration\n");
266
    usbs_serial_wait_until_configured();
267
    cyg_thread_delay((cyg_tick_count_t) 10);
268
 
269
    // ----- While configured read data & send out serial port -----
270
 
271
    DBG("Usb2Ser: USB configured\n");
272
    while (usbs_serial_is_configured()) {
273
      if ((c = getc(rxf)) < 0) {
274
        DBG("*** USB Read Error: %d ***\n", c);
275
      }
276
      else {
277
        char ch = (char) c;
278
        write(txh, &ch, 1);
279
      }
280
    }
281
  }
282
}
283
 
284
// --------------------------------------------------------------------------
285
// Thread receives packets from the serial port and sends them out the USB
286
// It uses a buffered stdio input, an un-buffered low-level file output.
287
// This isn't terribly efficient, but rather an example of both methods.
288
 
289
void ser2usb_func(cyg_addrword_t data)
290
{
291
  int  c;
292
  FILE *rxf = fopen(SER_DEV, "r");
293
  int  txh = open(USB_TX_DEV, O_WRONLY, 0);
294
 
295
  DBG("Ser2Usb: Thread starting\n");
296
 
297
  if (!rxf) {
298
    DBG("Error opening serial rx port\n");
299
    return;
300
  }
301
 
302
  if (txh < 0) {
303
    DBG("Error opening USB tx port\n");
304
    return;
305
  }
306
 
307
  while (1) {
308
 
309
    // ----- Wait for the host to configure -----
310
 
311
    DBG("Ser2Usb: Waiting for USB configuration\n");
312
    usbs_serial_wait_until_configured();
313
    cyg_thread_delay((cyg_tick_count_t) 10);
314
 
315
    // ----- While configured read data & send out serial port -----
316
 
317
    DBG("Ser2Usb: USB configured\n");
318
    while (usbs_serial_is_configured()) {
319
      if ((c = getc(rxf)) < 0) {
320
        DBG("*** Console Read Error: %d ***\n", c);
321
      }
322
      else {
323
        char ch = (char) c;
324
        write(txh, &ch, 1);
325
      }
326
    }
327
  }
328
}
329
 
330
// --------------------------------------------------------------------------
331
//  Application Startup
332
// --------------------------------------------------------------------------
333
 
334
void cyg_user_start(void)
335
{
336
  DBG("Entering cyg_user_start() function\n");
337
 
338
#ifdef CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM
339
  // Override the class handler to use ours.
340
  usbs_serial_ep0->class_control_fn = acm_class_handler;
341
#endif
342
 
343
  cyg_thread_create(4, usb2ser_func, (cyg_addrword_t) 0,
344
                    "Usb2Serial", (void *) stack[0], THREAD_STACK_SIZE,
345
                    &usb2ser_thread, &thread[0]);
346
 
347
  cyg_thread_create(4, ser2usb_func, (cyg_addrword_t) 1,
348
                    "Serial2Usb", (void *) stack[1], THREAD_STACK_SIZE,
349
                    &ser2usb_thread, &thread[1]);
350
 
351
  // Start USB subsystem
352
  usbs_serial_start();
353
 
354
  // Start the threads running.
355
  cyg_thread_resume(usb2ser_thread);
356
  cyg_thread_resume(ser2usb_thread);
357
}
358
 

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.