L1CTL_SIM_CONF,
L1CTL_TCH_MODE_REQ,
L1CTL_TCH_MODE_CONF,
+ L1CTL_VOICE_REQ,
+ L1CTL_VOICE_CONF,
+ L1CTL_VOICE_IND,
};
enum ccch_mode {
uint8_t data[23];
} __attribute__((packed));
+/* voice data from network */
+struct l1ctl_voice_ind {
+ uint8_t data[33];
+} __attribute__((packed));
+
/*
* uplink info
*/
uint8_t pad[3];
} __attribute__((packed));
+/* voice data to network */
+struct l1ctl_voice_req {
+ uint8_t data[33];
+} __attribute__((packed));
+
#endif /* __L1CTL_PROTO_H__ */
return 0;
}
+/* Receive L1CTL_VOICE_IND (Voice Indication from L1) */
+static int rx_l1_voice_ind(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct l1ctl_info_dl *dl;
+ struct l1ctl_voice_ind *vi;
+
+ /* Header handling */
+ dl = (struct l1ctl_info_dl *) msg->l1h;
+ msg->l2h = dl->payload;
+ vi = (struct l1ctl_voice_ind *) msg->l2h;
+
+ LOGP(DL1C, LOGL_INFO, "VOICE IND\n");
+
+ {
+ static FILE *out = NULL;
+ int i;
+
+ if (!out)
+ out = fopen("voice.raw", "wb");
+
+ fwrite(vi->data, 33, 1, out);
+
+ for (i=0; i<33; i++)
+ printf("%02x ", vi->data[i]);
+ printf("\n");
+ }
+
+ return 0;
+}
+
/* Receive incoming data from L1 using L1CTL format */
int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg)
{
case L1CTL_SIM_CONF:
rc = rx_l1_sim_conf(ms, msg);
break;
+ case L1CTL_VOICE_IND:
+ rc = rx_l1_voice_ind(ms, msg);
+ msgb_free(msg);
+ break;
default:
LOGP(DL1C, LOGL_ERROR, "Unknown MSG: %u\n", l1h->msg_type);
msgb_free(msg);
-include Makefile.inc
# Uncomment this line if you want to enable Tx (Transmit) Support.
-#CFLAGS += -DCONFIG_TX_ENABLE
+CFLAGS += -DCONFIG_TX_ENABLE
# Uncomment this line if you want to write to flash.
#CFLAGS += -DCONFIG_FLASH_WRITE
const char *hr = "======================================================================\n";
+/* SIM Stuff, TODO: clean it up */
+
+#include <calypso/sim.h>
+
+#include <l1ctl_proto.h>
+
+#define SIM_CLASS 0xA0 /* Class that contains the following instructions */
+#define SIM_GET_RESPONSE 0xC0 /* Get the response of a command from the card */
+#define SIM_READ_BINARY 0xB0 /* Read file in binary mode */
+
+#define L3_MSG_HEAD 4
+
+static uint8_t sim_data[256]; /* buffer for SIM command */
+static volatile uint16_t sim_len = 0; /* lenght of data in sim_data[] */
+
+void sim_apdu(uint16_t len, uint8_t *data)
+{
+ memcpy(sim_data, data, len);
+ sim_len = len;
+}
+
+/* allocate a large enough buffer for the SIM response */
+
+struct msgb *my_l1ctl_msgb_alloc(uint8_t msg_type)
+{
+ struct msgb *msg;
+ struct l1ctl_hdr *l1h;
+
+ msg = msgb_alloc_headroom(256, L3_MSG_HEAD, "l1ctl1");
+ if (!msg) {
+ while (1) {
+ puts("OOPS. Out of buffers...\n");
+ }
+
+ return NULL;
+ }
+ l1h = (struct l1ctl_hdr *) msgb_put(msg, sizeof(*l1h));
+ l1h->msg_type = msg_type;
+ l1h->flags = 0;
+
+ msg->l1h = (uint8_t *)l1h;
+
+ return msg;
+}
+
+static void sim_handler(void)
+{
+ uint8_t status_word[2];
+ struct msgb *msg;
+ uint8_t *dat;
+ uint16_t length;
+
+ if(sim_len) /* a new SIM command has arrived */
+ {
+ status_word[0] = 0;
+ status_word[1] = 0;
+
+ msg = my_l1ctl_msgb_alloc(L1CTL_SIM_CONF);
+
+ /* check if instructions expects a response (TODO: add more instructions */
+ if (/* GET RESPONSE needs SIM_APDU_GET */
+ (sim_len == 5 && sim_data[0] == SIM_CLASS &&
+ sim_data[1] == SIM_GET_RESPONSE && sim_data[2] == 0x00 &&
+ sim_data[3] == 0x00) ||
+ /* READ BINARY needs SIM_APDU_GET */
+ (sim_len >= 5 && sim_data[0] == SIM_CLASS &&
+ sim_data[1] == SIM_READ_BINARY))
+ {
+ /* allocate space for expected response */
+ length = sim_data[4];
+ dat = msgb_put(msg, length + 2);
+
+ 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)
+ puts("SIM ERROR !\n");
+ printf("Status 1: %02X %02X\n", status_word[0], status_word[1]);
+
+ /* copy status at the end */
+ memcpy(dat + length, status_word, 2);
+
+ l1_queue_for_l2(msg);
+ }
+ else
+ {
+ 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)
+ puts("SIM ERROR !\n");
+ printf("Status 2: %02X %02X\n", status_word[0], status_word[1]);
+
+ /* 2 bytes status */
+ length = 2;
+ dat = msgb_put(msg, length);
+ memcpy(dat, status_word, length);
+
+ l1_queue_for_l2(msg);
+ }
+
+ sim_len = 0;
+ }
+}
+
/* MAIN program **************************************************************/
static void key_handler(enum key_codes code, enum key_states state);
+/* called while waiting for SIM */
+
+void sim_wait_handler(void)
+{
+ l1a_compl_execute();
+ update_timers();
+}
+
int main(void)
{
+ uint8_t atr[20];
+ uint8_t atrLength = 0;
+
board_init();
puts("\n\nOSMOCOM Layer 1 (revision " GIT_REVISION ")\n");
display_set_attr(DISP_ATTR_INVERT);
display_puts("layer1.bin");
+ /* initialize SIM */
+ calypso_sim_init(sim_wait_handler);
+
+ puts("Power up simcard:\n");
+ memset(atr,0,sizeof(atr));
+ atrLength = calypso_sim_powerup(atr);
+
+
layer1_init();
tpu_frame_irq_en(1, 1);
while (1) {
l1a_compl_execute();
update_timers();
+ sim_handler();
}
/* NOT REACHED */
default:
break;
}
+ /* power down SIM, TODO: this will happen with every key pressed,
+ put it somewhere else ! */
+ calypso_sim_powerdown();
}
int i;
for(i=0;i<len;i++)
- printf("%x ",data[i]);
+ printf("%02x ",data[i]);
printf("(%i bytes)\n", len);
return;
}
-/* SIM instructions
+/* SIM instructions
All instructions a standard sim card must feature: */
#define SIM_CLASS 0xA0 /* Class that contains the following instructions */
#define SIM_SELECT 0xA4 /* Select a file on the card */
}
/* Get the status of the currently selected file */
-uint16_t sim_status(void)
+uint16_t sim_status(void)
{
uint8_t status_word[2];
return (status_word[0] << 8) | status_word[1];
}
+uint16_t sim_verify(char *pin)
+{
+ uint8_t txBuffer[8];
+ uint8_t status_word[2];
+
+ memset(txBuffer, 0xFF, 8);
+ memcpy(txBuffer, pin, strlen(pin));
+
+ if(calypso_sim_transceive(SIM_CLASS, SIM_VERIFY_CHV, 0x00, 0x01, 0x08, txBuffer,status_word, SIM_APDU_PUT) != 0)
+ return 0xFFFF;
+
+ return (status_word[0] << 8) | status_word[1];
+}
+
+uint16_t sim_run_gsm_algorith(uint8_t *data)
+{
+ uint8_t status_word[2];
+
+ if(calypso_sim_transceive(SIM_CLASS, SIM_RUN_GSM_ALGORITHM, 0x00, 0x00, 0x10, data, status_word, SIM_APDU_PUT) != 0)
+ return 0xFFFF;
+
+ printf(" ==> Status word: %x\n", (status_word[0] << 8) | status_word[1]);
+
+ if(status_word[0] != 0x9F || status_word[1] != 0x0C)
+ return (status_word[0] << 8) | status_word[1];
+
+ /* GET RESPONSE */
+
+ if(calypso_sim_transceive(SIM_CLASS, SIM_GET_RESPONSE, 0, 0, 0x0C, data ,status_word, SIM_APDU_GET) != 0)
+ return 0xFFFF;
+
+ return (status_word[0] << 8) | status_word[1];
+}
+
+
+/* FIXME: We need proper calibrated delay loops at some point! */
+void delay_us(unsigned int us)
+{
+ volatile unsigned int i;
+
+ for (i= 0; i < us*4; i++) { i; }
+}
+
+void delay_ms(unsigned int ms)
+{
+ volatile unsigned int i;
+ for (i= 0; i < ms*1300; i++) { i; }
+}
+
+
+
+
/* Execute my (dexter's) personal test */
void do_sim_test(void)
{
uint8_t atr[20];
uint8_t atrLength = 0;
-
+
memset(atr,0,sizeof(atr));
/* Initialize Sim-Controller driver */
puts("Initializing driver:\n");
- calypso_sim_init();
+ calypso_sim_init(NULL);
/* Power up sim and display ATR */
puts("Power up simcard:\n");
puts(" * Testing SELECT: Selecting DF_GSM\n");
printf(" ==> Status word: %x\n", sim_select(SIM_DF_GSM));
+ puts(" * Testing PIN VERIFY\n");
+ printf(" ==> Status word: %x\n", sim_verify("1234"));
+
puts(" * Testing SELECT: Selecting EF_IMSI\n");
printf(" ==> Status word: %x\n", sim_select(SIM_EF_IMSI));
printf(" ==> Status word: %x\n", sim_status());
memset(buffer,0,sizeof(buffer));
- puts(" * Testing READ BINARY:\n");
+ puts(" * Testing READ BINARY:\n");
printf(" ==> Status word: %x\n", sim_readbinary(0,0,9,buffer));
printf(" Data: ");
myHexdump(buffer,9);
+ memset(buffer,0,sizeof(buffer));
+ memcpy(buffer,"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff",16);
+ puts(" * Testing RUN GSM ALGORITHM\n");
+ printf(" ==> Status word: %x\n", sim_run_gsm_algorith(buffer));
+ printf(" Result: ");
+ myHexdump(buffer,12);
+
delay_ms(5000);
calypso_sim_powerdown();
#include <calypso/sim.h>
#include <calypso/irq.h>
-static int sim_rx_character_count = 0; /* How many bytes have been received by calypso_sim_receive() */
-static int sim_tx_character_count = 0; /* How many bytes have been transmitted by calypso_sim_transmit() */
-static int sim_tx_character_length = 0; /* How many bytes have to be transmitted by calypso_sim_transmit() */
+static void (*sim_wait_cb)(void) = NULL; /* called during waiting for SIM */
+static volatile uint8_t sim_ignore_waiting_char = 0; /* signal ignoring of NULL procedure byte */
+static volatile int sim_rx_character_count = 0; /* How many bytes have been received by calypso_sim_receive() */
+static volatile int sim_rx_max_character_count = 0; /* How many bytes have been received by calypso_sim_receive() */
+static volatile int sim_tx_character_count = 0; /* How many bytes have been transmitted by calypso_sim_transmit() */
+static volatile int sim_tx_character_length = 0; /* How many bytes have to be transmitted by calypso_sim_transmit() */
static uint8_t *rx_buffer = 0; /* RX-Buffer that is issued by calypso_sim_receive() */
static uint8_t *tx_buffer = 0; /* TX-Buffer that is issued by calypso_sim_transmit() */
volatile static int rxDoneFlag = 0; /* Used for rx synchronization instead of a semaphore in calypso_sim_receive() */
else
puts(" | |-REG_SIM_CONF1_CONFSCLKDIV = 0 ==> SIM clock frequency is 13/4 Mhz.\n");
delay_ms(SIM_DEBUG_OUTPUTDELAY);
-
+
if(regVal & REG_SIM_CONF1_CONFSCLKLEV)
puts(" | |-REG_SIM_CONF1_CONFSCLKLEV = 1 ==> SIM clock idle level is high.\n");
else
puts(" | |-REG_SIM_CONF1_CONFSCLKLEV = 0 ==> SIM clock idle level is low.\n");
delay_ms(SIM_DEBUG_OUTPUTDELAY);
-
+
if(regVal & REG_SIM_CONF1_CONFETUPERIOD)
puts(" | |-REG_SIM_CONF1_CONFETUPERIOD = 1 ==> ETU period is 512/8*1/Fsclk.\n");
else
puts(" | |-REG_SIM_CONF1_CONFETUPERIOD = 0 ==> ETU period is 372/8*1/Fsclk.\n");
delay_ms(SIM_DEBUG_OUTPUTDELAY);
-
+
if(regVal & REG_SIM_CONF1_CONFBYPASS)
puts(" | |-REG_SIM_CONF1_CONFBYPASS = 1 ==> Hardware timers and start and stop sequences are bypassed.\n");
else
puts(" | |-REG_SIM_CONF1_CONFBYPASS = 0 ==> Hardware timers and start and stop sequences are normal.\n");
delay_ms(SIM_DEBUG_OUTPUTDELAY);
-
+
if(regVal & REG_SIM_CONF1_CONFSVCCLEV)
puts(" | |-REG_SIM_CONF1_CONFSVCCLEV = 1 ==> SVCC Level is high (Only valid when CONFBYPASS = 1).\n");
else
int calypso_sim_powerup(uint8_t *atr)
{
/* Enable level shifters and voltage regulator */
+ #if 1 // 2.9V
twl3025_reg_write(VRPCSIM, VRPCSIM_SIMLEN | VRPCSIM_RSIMEN | VRPCSIM_SIMSEL);
+ #else // 1.8V
+ twl3025_reg_write(VRPCSIM, VRPCSIM_SIMLEN | VRPCSIM_RSIMEN);
+ #endif
#if (SIM_DEBUG == 1)
puts(" * Power enabled!\n");
#endif
/* Catch ATR */
if(atr != 0)
- return calypso_sim_receive(atr);
+ return calypso_sim_receive(atr, 0);
else
return 0;
}
/* Catch ATR */
if(atr != 0)
- return calypso_sim_receive(atr);
+ return calypso_sim_receive(atr, 0);
else
return 0;
}
/* Receive raw data through the sim interface */
-int calypso_sim_receive(uint8_t *data)
+int calypso_sim_receive(uint8_t *data, uint8_t len)
{
/* Prepare buffers and flags */
rx_buffer = data;
sim_rx_character_count = 0;
rxDoneFlag = 0;
+ sim_rx_max_character_count = len;
/* Switch I/O direction to input */
writew(readw(REG_SIM_CONF1) & ~REG_SIM_CONF1_CONFTXRX, REG_SIM_CONF1);
writew(~(REG_SIM_MASKIT_MASK_SIM_RX | REG_SIM_MASKIT_MASK_SIM_WT), REG_SIM_MASKIT);
/* Wait till rxDoneFlag is set */
- while(rxDoneFlag == 0);
+ while(rxDoneFlag == 0)
+ {
+ if(sim_wait_cb) (*sim_wait_cb)();
+ }
/* Disable all interrupt driven functions by masking all interrupts */
writew(0xFF, REG_SIM_MASKIT);
/* Hand back the number of bytes received */
return sim_rx_character_count;
-
+
return;
}
tx_buffer++;
sim_tx_character_count++;
- /* Wait till rxDoneFlag is set */
- while(txDoneFlag == 0);
+ /* Wait till xDoneFlag is set */
+ while(txDoneFlag == 0)
+ {
+ if(sim_wait_cb) (*sim_wait_cb)();
+ }
/* Disable all interrupt driven functions by masking all interrupts */
writew(0xFF, REG_SIM_MASKIT);
/* Display interrupt information */
#if (SIM_DEBUG == 1)
- puts("SIM-ISR: Interrupt caught: ");
+ puts("SIM-ISR: ");
#endif
if(regVal & REG_SIM_IT_SIM_NATR)
{
if(regVal & REG_SIM_IT_SIM_TX)
{
#if (SIM_DEBUG == 1)
- puts(" Waiting for character to transmit...\n");
+ puts(" Waiting for transmit...\n");
#endif
if(sim_tx_character_count >= sim_tx_character_length)
+ {
txDoneFlag = 1;
+ }
else
{
writew(*tx_buffer,REG_SIM_DTX);
tx_buffer++;
sim_tx_character_count++;
+
+ #if 1 /* Dieter: set to 0 to get problems with some cards */
+ /* its essential to immediately switch to RX after TX is done */
+ if(sim_tx_character_count >= sim_tx_character_length)
+ {
+ /* TODO: set a proper delay here, 4 is to
+ long if not debugging and no delay is too short */
+ delay_ms(1);
+ /* Switch I/O direction to input */
+ writew(readw(REG_SIM_CONF1) & ~REG_SIM_CONF1_CONFTXRX, REG_SIM_CONF1);
+ }
+ #endif
}
}
/* Used by: calypso_sim_receive() to receive the incoming data */
if(regVal & REG_SIM_IT_SIM_RX)
{
+ uint8_t ch = (uint8_t) (readw(REG_SIM_DRX) & 0xFF);
+ /* ignore NULL procedure byte */
+ if(ch == 0x60 && sim_ignore_waiting_char)
+ {
#if (SIM_DEBUG == 1)
- puts(" Waiting characters to be read...\n");
+ puts(" 0x60 received...\n");
+#endif
+ return;
+ }
+
+#if (SIM_DEBUG == 1)
+ printf(" Waiting for read (%02X)...\n", ch);
#endif
/* Increment character count - this is what calypso_sim_receive() hands back */
sim_rx_character_count++;
/* Read byte from rx-fifo and write it to the issued buffer */
- *rx_buffer = (uint8_t) (readw(REG_SIM_DRX) & 0xFF);
+ *rx_buffer = ch;
rx_buffer++;
+
+ /* to maximise SIM access speed, stop waiting after
+ all the expected characters have been received. */
+ if(sim_rx_max_character_count && sim_rx_character_count >= sim_rx_max_character_count) {
+#if (SIM_DEBUG == 1)
+ puts(" Max characters received!\n");
+#endif
+ rxDoneFlag = 1;
+ }
}
}
uint8_t *status, /* Status word (2 byte array, see note 1) */
uint8_t mode) /* Mode of operation: 1=GET, 0=PUT */
- /* Note 1: You can use a null-pointer (0) if you are not interested in
+ /* Note 1: You can use a null-pointer (0) if you are not interested in
the status word */
{
uint8_t transmissionBuffer[256];
#if (SIM_DEBUG == 1)
puts("SIM-T0: Case 1: No input, No Output (See also GSM 11.11 Page 34)\n");
#endif
- numberOfReceivedBytes = calypso_sim_receive(transmissionBuffer);
-
+ numberOfReceivedBytes = calypso_sim_receive(transmissionBuffer, 2);
+
if(numberOfReceivedBytes == 2)
{
#if (SIM_DEBUG == 1)
{
status[0] = transmissionBuffer[0];
status[1] = transmissionBuffer[1];
- }
+ }
return 0;
}
puts("SIM-T0: Case 2: No input / Output of known length (See also GSM 11.11 Page 34)\n");
#endif
- numberOfReceivedBytes = calypso_sim_receive(transmissionBuffer);
+ /* TODO: waiting for one character is only OK if no error occurs */
+ numberOfReceivedBytes = calypso_sim_receive(transmissionBuffer, 1);
/* Error situation: The card has aborted, sends no data but a status word */
if(numberOfReceivedBytes == 2)
{
status[0] = transmissionBuffer[0];
status[1] = transmissionBuffer[1];
- }
+ }
return 0;
}
- /* Acknoledge byte received */
+ /* Acknowledge byte received */
else if(numberOfReceivedBytes == 1)
{
#if (SIM_DEBUG == 1)
{
#if (SIM_DEBUG == 1)
puts("SIM-T0: T0 Protocol error: Invalid ACK byte -- aborting!\n");
-#endif
+#endif
return -1;
}
/* Transmit body */
calypso_sim_transmit(data,p3le);
-
+
+ /* Ignore waiting char for RUN GSM ALGORITHM */
+ /* TODO: implement proper handling of the "Procedure Bytes"
+ than this is no longer needed */
+ if(ins == 0x88)
+ sim_ignore_waiting_char = 1;
/* Receive status word */
- numberOfReceivedBytes = calypso_sim_receive(transmissionBuffer);
+ numberOfReceivedBytes = calypso_sim_receive(transmissionBuffer, 2);
+ sim_ignore_waiting_char = 0;
/* Check status word */
if(numberOfReceivedBytes == 2)
{
#if (SIM_DEBUG == 1)
puts("SIM-T0: T0 Protocol error: Missing or invalid status word -- aborting!\n");
-#endif
+#endif
return -1;
}
}
puts("SIM-T0: Case 4: Input / No output (See also GSM 11.11 Page 34)\n");
#endif
- numberOfReceivedBytes = calypso_sim_receive(data);
+ numberOfReceivedBytes = calypso_sim_receive(data, p3le + 1 + 2);
/* Error situation: The card has aborted, sends no data but a status word */
if(numberOfReceivedBytes == 2)
{
status[0] = data[0];
status[1] = data[1];
- }
+ }
return 0;
}
{
#if (SIM_DEBUG == 1)
puts("SIM-T0: T0 Protocol error: Invalid ACK byte -- aborting!\n");
-#endif
+#endif
return -1;
}
{
status[0] = data[p3le + 1];
status[1] = data[p3le + 2];
- }
-
+ }
+
/* Move data one position left to cut away the ACK-Byte */
memcpy(data,data+1,p3le);
/* Initialize simcard interface */
-void calypso_sim_init(void)
+void calypso_sim_init(void (cb)(void))
{
/* Register IRQ handler and turn interrupts on */
#if (SIM_DEBUG == 1)
puts("SIM: Registering interrupt handler for simcard-interface\n");
#endif
irq_register_handler(IRQ_SIMCARD, &sim_irq_handler);
+ #if 1
irq_config(IRQ_SIMCARD, 0, 0, 0xff);
+ #else
+ irq_config(IRQ_SIMCARD, 0, 0, 1);
+ #endif
irq_enable(IRQ_SIMCARD);
+
+ sim_wait_cb = cb;
}
the status word */
/* Transmission of raw data */
-int calypso_sim_receive(uint8_t *data); /* Receive raw data through the sim interface */
+int calypso_sim_receive(uint8_t *data, uint8_t len); /* Receive raw data through the sim interface */
int calypso_sim_transmit(uint8_t *data, int length); /* Transmit raw data through the sim interface */
-void calypso_sim_init(void); /* Initialize simcard interface */
+void calypso_sim_init(void (cb)(void)); /* Initialize simcard interface */
/* Known Bugs:
/* the size we will allocate struct msgb* for HDLC */
#define L3_MSG_HEAD 4
-#define L3_MSG_SIZE (sizeof(struct l1ctl_hdr)+sizeof(struct l1ctl_info_dl)+sizeof(struct l1ctl_data_ind) + L3_MSG_HEAD)
+#define L3_MSG_SIZE (sizeof(struct l1ctl_hdr)+sizeof(struct l1ctl_info_dl)+sizeof(struct l1ctl_voice_ind) + L3_MSG_HEAD)
void l1_queue_for_l2(struct msgb *msg)
{
l1ctl_tx_tch_mode_conf(tch_mode);
}
+#include <calypso/sim.h>
+
+void sim_apdu(uint16_t len, uint8_t *data);
+
+static void l1ctl_sim_req(struct msgb *msg)
+{
+ uint16_t len = msg->len - sizeof(struct l1ctl_hdr);
+ uint8_t *data = msg->data + sizeof(struct l1ctl_hdr);
+
+#if 1 /* for debugging only */
+ {
+ int i;
+ printf("SIM Request (%u): ", len);
+ for (i = 0; i < len; i++)
+ printf("%02x ", data[i]);
+ puts("\n");
+ }
+#endif
+
+ sim_apdu(len, data);
+}
+
/* callback from SERCOMM when L2 sends a message to L1 */
static void l1a_l23_rx_cb(uint8_t dlci, struct msgb *msg)
{
case L1CTL_TCH_MODE_REQ:
l1ctl_rx_tch_mode_req(msg);
break;
+ case L1CTL_SIM_REQ:
+ l1ctl_sim_req(msg);
+ break;
}
exit_msgbfree:
traffic_buf = tch_sub ? dsp_api.ndb->a_dd_1 : dsp_api.ndb->a_dd_0;
if (traffic_buf[0] & (1<<B_BLUD)) {
+
+ if (!(dsp_api.ndb->a_dd_0[0] & (1<<B_BFI))) {
+ int i,j;
+
+ /* TCH/F data */
+ struct msgb *msg = l1ctl_msgb_alloc(L1CTL_VOICE_IND);
+
+ struct l1ctl_info_dl *dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl));
+ struct l1ctl_voice_ind *vi = (struct l1ctl_voice_ind *) msgb_put(msg, sizeof(*vi));
+
+ /* FIXME fill dl */
+
+ for (j = 0,i = 3; j < 32; j+=2,i++) {
+ uint16_t w = dsp_api.ndb->a_dd_0[i];
+ vi->data[j ] = (w >> 8) & 0xff;
+ vi->data[j+1] = w & 0xff;
+ }
+ vi->data[32] = (dsp_api.ndb->a_dd_0[19] >> 8) & 0xff;
+
+
+ l1_queue_for_l2(msg);
+ }
+
/* Reset traffic buffer header in NDB (needed by DSP) */
traffic_buf[0] = 0;
traffic_buf[2] = 0xffff;
static inline void check_lost_frame(void)
{
+ static int last_ts = -1;
int diff, timestamp = hwtimer_read(1);
if (last_timestamp < timestamp)
diff = last_timestamp - timestamp;
+ /* TS change compensation */
+ if (l1s.dedicated.type) {
+ if (l1s.dedicated.tn < last_ts) {
+ int ediff = ((8 - last_ts + l1s.dedicated.tn) * TIMER_TICKS_PER_TDMA) >> 3;
+ printf("TS Chg: %d -> %d | %d %d\n",
+ last_ts, l1s.dedicated.tn, diff, ediff);
+
+ // if (((ediff - 2) < diff) && ((ediff + 2) > diff)) {
+ puts("ADV !\n");
+ l1s.current_time = l1s.next_time;
+ l1s_time_inc(&l1s.next_time, 1);
+ // }
+ }
+ last_ts = l1s.dedicated.tn;
+ }
+
/* allow for a bit of jitter */
if (diff < TIMER_TICKS_PER_TDMA - TIMER_TICK_JITTER ||
diff > TIMER_TICKS_PER_TDMA + TIMER_TICK_JITTER)