[WIP] target/fw/sim: SIM Layer 1 driver
[osmocom-bb.git] / src / target / firmware / apps / layer1 / main.c
1 /* main program of Free Software for Calypso Phone */
2
3 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
4  *
5  * All Rights Reserved
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22
23 #include <stdint.h>
24 #include <stdio.h>
25
26 #include <debug.h>
27 #include <memory.h>
28 #include <delay.h>
29 #include <rffe.h>
30 #include <keypad.h>
31 #include <board.h>
32
33 #include <abb/twl3025.h>
34 #include <display.h>
35 #include <rf/trf6151.h>
36
37 #include <comm/sercomm.h>
38 #include <comm/timer.h>
39
40 #include <calypso/clock.h>
41 #include <calypso/tpu.h>
42 #include <calypso/tsp.h>
43 #include <calypso/irq.h>
44 #include <calypso/misc.h>
45
46 #include <layer1/sync.h>
47 #include <layer1/tpu_window.h>
48
49 const char *hr = "======================================================================\n";
50
51 /* SIM Stuff, TODO: clean it up */
52
53 #include <calypso/sim.h>
54
55 #include <l1ctl_proto.h>
56
57 #define SIM_CLASS               0xA0    /* Class that contains the following instructions */
58 #define SIM_GET_RESPONSE        0xC0    /* Get the response of a command from the card */
59 #define SIM_READ_BINARY         0xB0    /* Read file in binary mode */
60
61 #define L3_MSG_HEAD 4
62
63 static uint8_t sim_data[256]; /* buffer for SIM command */
64 static volatile uint16_t sim_len = 0; /* lenght of data in sim_data[] */
65
66 void sim_apdu(uint16_t len, uint8_t *data)
67 {
68         memcpy(sim_data, data, len);
69         sim_len = len;
70 }
71
72 /* allocate a large enough buffer for the SIM response */
73
74 struct msgb *my_l1ctl_msgb_alloc(uint8_t msg_type)
75 {
76         struct msgb *msg;
77         struct l1ctl_hdr *l1h;
78
79         msg = msgb_alloc_headroom(256, L3_MSG_HEAD, "l1ctl1");
80         if (!msg) {
81                 while (1) {
82                         puts("OOPS. Out of buffers...\n");
83                 }
84
85                 return NULL;
86         }
87         l1h = (struct l1ctl_hdr *) msgb_put(msg, sizeof(*l1h));
88         l1h->msg_type = msg_type;
89         l1h->flags = 0;
90
91         msg->l1h = (uint8_t *)l1h;
92
93         return msg;
94 }
95
96 static void sim_handler(void)
97 {
98         uint8_t status_word[2];
99         struct msgb *msg;
100         uint8_t *dat;
101         uint16_t length;
102
103         if(sim_len) /* a new SIM command has arrived */
104         {
105                 status_word[0] = 0;
106                 status_word[1] = 0;
107
108                 msg = my_l1ctl_msgb_alloc(L1CTL_SIM_CONF);
109
110                 /* check if instructions expects a response (TODO: add more instructions */
111                 if (/* GET RESPONSE needs SIM_APDU_GET */
112                     (sim_len == 5 && sim_data[0] == SIM_CLASS &&
113                      sim_data[1] == SIM_GET_RESPONSE && sim_data[2] == 0x00 &&
114                      sim_data[3] == 0x00) ||
115                     /* READ BINARY needs SIM_APDU_GET */
116                      (sim_len >= 5 && sim_data[0] == SIM_CLASS &&
117                       sim_data[1] == SIM_READ_BINARY))
118                 {
119                         /* allocate space for expected response */
120                         length = sim_data[4];
121                         dat = msgb_put(msg, length + 2);
122
123                         if(calypso_sim_transceive(sim_data[0], sim_data[1], sim_data[2], sim_data[3], sim_data[4], dat, status_word, SIM_APDU_GET) != 0)
124                                 puts("SIM ERROR !\n");
125                         printf("Status 1: %02X %02X\n", status_word[0], status_word[1]);
126
127                         /* copy status at the end */
128                         memcpy(dat + length, status_word, 2);
129
130                         l1_queue_for_l2(msg);
131                 }
132                 else
133                 {
134                         if(calypso_sim_transceive(sim_data[0], sim_data[1], sim_data[2], sim_data[3], sim_data[4], &sim_data[5], status_word, SIM_APDU_PUT) != 0)
135                                 puts("SIM ERROR !\n");
136                         printf("Status 2: %02X %02X\n", status_word[0], status_word[1]);
137
138                         /* 2 bytes status */
139                         length = 2;
140                         dat = msgb_put(msg, length);
141                         memcpy(dat, status_word, length);
142
143                         l1_queue_for_l2(msg);
144                 }
145
146                 sim_len = 0;
147         }
148 }
149
150 /* MAIN program **************************************************************/
151
152 static void key_handler(enum key_codes code, enum key_states state);
153
154 /* called while waiting for SIM */
155
156 void sim_wait_handler(void)
157 {
158         l1a_compl_execute();
159         update_timers();
160 }
161
162 int main(void)
163 {
164         uint8_t atr[20];
165         uint8_t atrLength = 0;
166
167         board_init();
168
169         puts("\n\nOSMOCOM Layer 1 (revision " GIT_REVISION ")\n");
170         puts(hr);
171
172         /* Dump device identification */
173         dump_dev_id();
174         puts(hr);
175
176         keypad_set_handler(&key_handler);
177
178         /* Dump clock config after PLL set */
179         calypso_clk_dump();
180         puts(hr);
181
182         display_set_attr(DISP_ATTR_INVERT);
183         display_puts("layer1.bin");
184
185         /* initialize SIM */
186         calypso_sim_init(sim_wait_handler);
187
188         puts("Power up simcard:\n");
189         memset(atr,0,sizeof(atr));
190         atrLength = calypso_sim_powerup(atr);
191
192
193         layer1_init();
194
195         tpu_frame_irq_en(1, 1);
196
197         while (1) {
198                 l1a_compl_execute();
199                 update_timers();
200                 sim_handler();
201         }
202
203         /* NOT REACHED */
204
205         twl3025_power_off();
206 }
207
208 static int8_t vga_gain = 40;
209 static int high_gain = 0;
210 static int afcout = 0;
211
212 static void update_vga_gain(void)
213 {
214         printf("VGA Gain: %u %s\n", vga_gain, high_gain ? "HIGH" : "LOW");
215         trf6151_set_gain(vga_gain, high_gain);
216         tpu_enq_sleep();
217         tpu_enable(1);
218         tpu_wait_idle();
219 }
220
221 static void tspact_toggle(uint8_t num)
222 {
223         printf("TSPACT%u toggle\n", num);
224         tsp_act_toggle((1 << num));
225         tpu_enq_sleep();
226         tpu_enable(1);
227         tpu_wait_idle();
228 }
229
230 static void key_handler(enum key_codes code, enum key_states state)
231 {
232         if (state != PRESSED)
233                 return;
234
235         switch (code) {
236         case KEY_1:     /* VGA gain decrement */
237                 vga_gain -= 2;
238                 if (vga_gain < 14)
239                         vga_gain = 14;
240                 update_vga_gain();
241                 break;
242         case KEY_2:     /* High/Low Rx gain */
243                 high_gain ^= 1;
244                 update_vga_gain();
245                 break;
246         case KEY_3:     /* VGA gain increment */
247                 vga_gain += 2;
248                 if (vga_gain > 40)
249                         vga_gain = 40;
250                 update_vga_gain();
251                 break;
252         case KEY_4:
253                 tspact_toggle(6);       /* TRENA (RFFE) */
254                 break;
255         case KEY_5:
256                 tspact_toggle(8);       /* GSM_TXEN (RFFE) */
257                 break;
258         case KEY_6:
259                 tspact_toggle(1);       /* PAENA (RFFE) */
260                 break;
261         case KEY_7:                     /* decrement AFC OUT */
262                 afcout -= 100;
263                 if (afcout < -4096)
264                         afcout = -4096;
265                 twl3025_afc_set(afcout);
266                 printf("AFC OUT: %u\n", twl3025_afcout_get());
267                 break;
268         case KEY_9:                     /* increase AFC OUT */
269                 afcout += 100;
270                 if (afcout > 4095)
271                         afcout = 4095;
272                 twl3025_afc_set(afcout);
273                 printf("AFC OUT: %u\n", twl3025_afcout_get());
274                 break;
275         default:
276                 break;
277         }
278         /* power down SIM, TODO:  this will happen with every key pressed,
279        put it somewhere else ! */
280         calypso_sim_powerdown();
281 }
282
283