]> rtime.felk.cvut.cz Git - frescor/fna.git/blob - src_frescan/frescan_hw_buffer.c
abort when higher prio frame
[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  * See MaRTE OS license
23  *
24  */
25
26 #include "frescan_hw_buffer.h"
27
28 #include <string.h> // memcpy
29
30 #include "frescan_data.h"    // the_networks
31 #include "frescan_debug.h"   // DEBUG, ERROR
32 #include "frescan_servers.h" // frescan_servers_get_highest_prio
33 #include "frescan_queues.h"  // frescan_pqueue_xxx, frescan_servers_dequeue
34 #include "frescan_id.h"      // frescan_id_set_field
35
36 /**
37  * frescan_hw_buffer_abort - abort the packet in the hw tx buffer
38  *
39  * This function aborts the packet that is currently in the hw transmission
40  * buffer of the chip. It is useful to prevent priority inversion when there
41  * is another packet with highest priority waiting in the frescan queues.
42  *
43  * NOTE: if the frame is already being transmitted it won't abort it. In both
44  * cases a IRQ will be raised and either 'frescan_hook_frame_sent' or
45  * 'frescan_hook_frame_aborted' will be called.
46  */
47
48 int frescan_hw_buffer_abort(frescan_network_t net)
49 {
50         int ret;
51
52         ret = ioctl(the_networks[net].fd, CAN_IOCTL_ABORT_FRAME, NULL);
53         if (ret == -1) {
54                 ERROR ("could not abort the frame\n");
55                 return -1;
56         }
57
58         return 0;
59 }
60
61 /**
62  * frescan_hw_buffer_update - update the hw tx buffer
63  *
64  * This function updates the hw tx buffer with the packet with highest
65  * priority (including fp packets and server packets).
66  *
67  * TODO: use copy of pointer
68  */
69
70 int frescan_hw_buffer_update(frescan_network_t net)
71 {
72         int ret;
73         bool is_frame_in_chip, is_fp_highest_prio;
74         uint32_t frag_flag;
75         frescan_packet_t *packet;
76         frescan_prio_queue_t *pqueue;
77         frescan_prio_t fprio, sprio, prio;
78         frescan_ss_t id;
79
80         ret = frescan_servers_get_highest_prio(net, &id, &sprio);
81         if (ret != 0) return ret;
82
83         pqueue = the_networks[net].queues.tx_fp_queue;
84
85         ret = frescan_pqueue_get_highest_prio(pqueue, &packet, &fprio);
86         if (ret != 0) return ret;
87
88         if ((id == FRESCAN_MX_IDS) && (packet == NULL)) {
89                 DEBUG(FRESCAN_HW_BUFFER_ENABLE_DEBUG, "(ss:0 fp:0)\n");
90                 return 0;
91         }
92
93         if ((id != FRESCAN_MX_IDS) && (packet == NULL)) {
94                 DEBUG(FRESCAN_HW_BUFFER_ENABLE_DEBUG, "(ss:1 fp:0)\n");
95                 is_fp_highest_prio = false;
96         }
97
98         if ((id == FRESCAN_MX_IDS) && (packet != NULL)) {
99                 DEBUG(FRESCAN_HW_BUFFER_ENABLE_DEBUG, "(ss:0 fp:1)\n");
100                 is_fp_highest_prio = true;
101         }
102
103         if ((id != FRESCAN_MX_IDS) && (packet != NULL)) {
104                 DEBUG(FRESCAN_HW_BUFFER_ENABLE_DEBUG, "(ss:1 fp:1)\n");
105                 is_fp_highest_prio = (fprio > sprio);
106         }
107
108         prio = (is_fp_highest_prio) ? fprio : sprio;
109         is_frame_in_chip = (the_networks[net].last_packet != NULL);
110
111         if (is_frame_in_chip &&
112            (prio > the_networks[net].last_packet_prio)) {
113                 DEBUG(FRESCAN_HW_BUFFER_ENABLE_DEBUG,"abort frame\n");
114                 ret = frescan_hw_buffer_abort(net);
115                 if (ret != 0) {
116                         ERROR ("could not abort frame\n");
117                         return ret;
118                 }
119                 return 0;
120         }
121
122         if (is_fp_highest_prio) {
123                 ret = frescan_pqueue_dequeue(pqueue, &packet, &prio, 0);
124                 if (ret != 0) return ret;
125         } else {
126                 ret = frescan_servers_dequeue(net, id, &packet, &prio);
127                 if (ret != 0) return ret;
128
129                 frescan_id_set_field(&packet->frame->id,
130                                       FRESCAN_FIELD_PRIO,
131                                       (uint32_t)prio);
132         }
133
134         if (packet->buffer_pending_bytes > 8) {
135                 packet->frame->dlc = 8;
136         } else {
137                 packet->frame->dlc = packet->buffer_pending_bytes;
138         }
139
140         memcpy(packet->frame->data,
141                packet->buffer_read_pointer,
142                packet->frame->dlc);
143
144         packet->buffer_pending_bytes -= packet->frame->dlc;
145         packet->buffer_read_pointer  += packet->frame->dlc;
146
147         frag_flag = (packet->buffer_pending_bytes > 0) ? 1 : 0;
148         frescan_id_set_field
149                         (&packet->frame->id, FRESCAN_FIELD_FRAG_FLAG, frag_flag);
150
151         the_networks[net].last_packet = packet;
152         the_networks[net].last_packet_prio = prio;
153
154         DEBUG(FRESCAN_HW_BUFFER_ENABLE_DEBUG,
155               "frame->id:0x%X pend_bytes:%u dlc:%u fflag:%u\n",
156               packet->frame->id,
157               packet->buffer_pending_bytes,
158               packet->frame->dlc,
159               frag_flag);
160
161         ret = write(the_networks[net].fd,
162                     (void *)packet->frame,
163                     sizeof(struct can_frame_t));
164
165         if (ret != sizeof(struct can_frame_t)) {
166                 ERROR ("could not send frame\n");
167                 return ret;
168         }
169
170         return 0;
171 }