]> rtime.felk.cvut.cz Git - frescor/fna.git/blob - src_frescan/frescan_hw_buffer.c
6fc886ebc4bb9d6f420603682ba3605063de3fd9
[frescor/fna.git] / src_frescan / frescan_hw_buffer.c
1 /*!
2  * @file frescan_hw_buffer.c
3  *
4  * @brief functions to manage the hw transmission buffer
5  *
6  * @version 0.01
7  *
8  * @date 12-Mar-2008
9  *
10  * @author
11  *      Daniel Sangorrin
12  *
13  * @comments
14  *
15  * This file contains the functions needed to manage the hw transmission buffer.
16  * This is needed to update the transmission buffer of the CAN chip with the
17  * message with highest priority. This could involve having to abort the
18  * frame that is currently in the buffer.
19  *
20  * @license
21  *
22  * -----------------------------------------------------------------------
23  *  Copyright (C) 2006 - 2008 FRESCOR consortium partners:
24  *
25  *    Universidad de Cantabria,              SPAIN
26  *    University of York,                    UK
27  *    Scuola Superiore Sant'Anna,            ITALY
28  *    Kaiserslautern University,             GERMANY
29  *    Univ. Politécnica  Valencia,           SPAIN
30  *    Czech Technical University in Prague,  CZECH REPUBLIC
31  *    ENEA                                   SWEDEN
32  *    Thales Communication S.A.              FRANCE
33  *    Visual Tools S.A.                      SPAIN
34  *    Rapita Systems Ltd                     UK
35  *    Evidence                               ITALY
36  *
37  *    See http://www.frescor.org for a link to partners' websites
38  *
39  *           FRESCOR project (FP6/2005/IST/5-034026) is funded
40  *        in part by the European Union Sixth Framework Programme
41  *        The European Union is not liable of any use that may be
42  *        made of this code.
43  *
44  *  This file is part of FRESCAN
45  *
46  *  FRESCAN is free software; you can  redistribute it and/or  modify
47  *  it under the terms of  the GNU General Public License as published by
48  *  the Free Software Foundation;  either  version 2, or (at  your option)
49  *  any later version.
50  *
51  *  FRESCAN  is distributed  in  the hope  that  it  will  be useful,  but
52  *  WITHOUT  ANY  WARRANTY;     without  even the   implied   warranty  of
53  *  MERCHANTABILITY  or  FITNESS FOR  A  PARTICULAR PURPOSE. See  the  GNU
54  *  General Public License for more details.
55  *
56  *  You should have  received a  copy of  the  GNU  General Public License
57  *  distributed  with  FRESCAN;  see file COPYING.   If not,  write to the
58  *  Free Software  Foundation,  59 Temple Place  -  Suite 330,  Boston, MA
59  *  02111-1307, USA.
60  *
61  * As a special exception, including FRESCAN header files in a file,
62  * instantiating FRESCAN generics or templates, or linking other files
63  * with FRESCAN objects to produce an executable application, does not
64  * by itself cause the resulting executable application to be covered
65  * by the GNU General Public License. This exception does not
66  * however invalidate any other reasons why the executable file might be
67  * covered by the GNU Public License.
68  * -----------------------------------------------------------------------
69  *
70  */
71
72 #include "frescan_hw_buffer.h"
73
74 #include <string.h> // memcpy
75
76 #include "frescan_data.h"    // frescan_data
77 #include "frescan_debug.h"   // DEBUG, FRESCAN_ERROR
78 #include "frescan_servers.h" // frescan_servers_get_highest_prio
79 #include "frescan_queues.h"  // frescan_pqueue_xxx, frescan_servers_dequeue
80 #include "frescan_id.h"      // frescan_id_set_field
81
82 /**
83  * frescan_hw_buffer_abort - abort the packet in the hw tx buffer
84  *
85  * This function aborts the packet that is currently in the hw transmission
86  * buffer of the chip. It is useful to prevent priority inversion when there
87  * is another packet with highest priority waiting in the frescan queues.
88  *
89  * NOTE: if the frame is already being transmitted it won't abort it. In both
90  * cases a IRQ will be raised and either 'frescan_hook_frame_sent' or
91  * 'frescan_hook_frame_aborted' will be called.
92  */
93
94 int frescan_hw_buffer_abort(frescan_network_t net)
95 {
96         int ret;
97
98         ret = ioctl(frescan_data[net].fd, CAN_IOCTL_ABORT_FRAME, NULL);
99         if (ret == -1) {
100                 FRESCAN_ERROR ("could not abort the frame\n");
101                 return -1;
102         }
103
104         return 0;
105 }
106
107 /**
108  * frescan_hw_buffer_update - update the hw tx buffer
109  *
110  * This function updates the hw tx buffer with the packet with highest
111  * priority (including fp packets and server packets).
112  *
113  * TODO: use copy of pointer
114  */
115
116 int frescan_hw_buffer_update(frescan_network_t net)
117 {
118         int ret;
119         bool is_frame_in_chip, is_fp_highest_prio;
120         uint32_t frag_flag;
121         frescan_packet_t *packet;
122         frescan_prio_queue_t *pqueue;
123         frescan_prio_t fprio, sprio, prio;
124         frescan_ss_t id;
125
126         ret = frescan_servers_get_highest_prio(net, &id, &sprio);
127         if (ret != 0) return ret;
128
129         pqueue = frescan_data[net].queues.tx_fp_queue;
130
131         ret = frescan_pqueue_get_highest_prio(pqueue, &packet, &fprio);
132         if (ret != 0) return ret;
133
134         if ((id == FRESCAN_MX_IDS) && (packet == NULL)) {
135                 DEBUG(FRESCAN_HW_BUFFER_ENABLE_DEBUG, "(ss:0 fp:0)\n");
136                 return 0;
137         }
138
139         if ((id != FRESCAN_MX_IDS) && (packet == NULL)) {
140                 DEBUG(FRESCAN_HW_BUFFER_ENABLE_DEBUG, "(ss:1 fp:0)\n");
141                 is_fp_highest_prio = false;
142         }
143
144         if ((id == FRESCAN_MX_IDS) && (packet != NULL)) {
145                 DEBUG(FRESCAN_HW_BUFFER_ENABLE_DEBUG, "(ss:0 fp:1)\n");
146                 is_fp_highest_prio = true;
147         }
148
149         if ((id != FRESCAN_MX_IDS) && (packet != NULL)) {
150                 DEBUG(FRESCAN_HW_BUFFER_ENABLE_DEBUG, "(ss:1 fp:1)\n");
151                 is_fp_highest_prio = (fprio > sprio);
152         }
153
154         prio = (is_fp_highest_prio) ? fprio : sprio;
155         is_frame_in_chip = (frescan_data[net].last_packet != NULL);
156
157         if (is_frame_in_chip &&
158            (prio > frescan_data[net].last_packet_prio)) {
159                 DEBUG(FRESCAN_HW_BUFFER_ENABLE_DEBUG,"abort frame\n");
160                 ret = frescan_hw_buffer_abort(net);
161                 if (ret != 0) {
162                         FRESCAN_ERROR ("could not abort frame\n");
163                         return ret;
164                 }
165                 return 0;
166         }
167
168         if (is_fp_highest_prio) {
169                 ret = frescan_pqueue_dequeue(pqueue, &packet, &prio, 0);
170                 if (ret != 0) return ret;
171         } else {
172                 ret = frescan_servers_dequeue(net, id, &packet, &prio);
173                 if (ret != 0) return ret;
174
175                 frescan_id_set_field(&packet->frame->id,
176                                       FRESCAN_FIELD_PRIO,
177                                       (uint32_t)prio);
178         }
179
180         if (packet->buffer_pending_bytes > 8) {
181                 packet->frame->dlc = 8;
182         } else {
183                 packet->frame->dlc = packet->buffer_pending_bytes;
184         }
185
186         memcpy(packet->frame->data,
187                packet->buffer_read_pointer,
188                packet->frame->dlc);
189
190         packet->buffer_pending_bytes -= packet->frame->dlc;
191         packet->buffer_read_pointer  += packet->frame->dlc;
192
193         frag_flag = (packet->buffer_pending_bytes > 0) ? 1 : 0;
194         frescan_id_set_field
195                         (&packet->frame->id, FRESCAN_FIELD_FRAG_FLAG, frag_flag);
196
197         frescan_data[net].last_packet = packet;
198         frescan_data[net].last_packet_prio = prio;
199
200         DEBUG(FRESCAN_HW_BUFFER_ENABLE_DEBUG,
201               "frame->id:0x%X pend_bytes:%u dlc:%u fflag:%u\n",
202               packet->frame->id,
203               packet->buffer_pending_bytes,
204               packet->frame->dlc,
205               frag_flag);
206
207         ret = write(frescan_data[net].fd,
208                     (void *)packet->frame,
209                     sizeof(struct can_frame_t));
210
211         if (ret != sizeof(struct can_frame_t)) {
212                 FRESCAN_ERROR ("could not send frame\n");
213                 return ret;
214         }
215
216         return 0;
217 }