📄 rlp-common.c
字号:
/* $Id: rlp-common.c,v 1.15 2004/02/20 11:02:25 uid66849 Exp $ G N O K I I A Linux/Unix toolset and driver for Nokia mobile phones. This file is part of gnokii. Gnokii is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Gnokii is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with gnokii; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Copyright (C) 1999, 2000 Hugh Blemings & Pavel Jan韐 ml. The development of RLP protocol is sponsored by SuSE CR, s.r.o. (Pavel use the SIM card from SuSE for testing purposes). Actual implementation of RLP protocol. Based on GSM 04.22 version 7.1.0, downloadable from www.etsi.org (if you register with them)*/#include <stdio.h>#include <string.h>#include <ctype.h>#include <stdlib.h>#include "config.h"#include "compat.h"#include "gnokii.h"#include "data/rlp-crc24.h"#include "misc.h" /* For u8, u32 etc. */#ifdef WIN32# define INLINE __inline#else# define INLINE inline#endif#ifndef RLP_DEBUG# define rlpprintf(a...) do { } while (0)#else# define rlpprintf(a...) do { gn_log_rlpdebug(a); } while (0)#endif/* Our state machine which handles all of nine possible states of RLP machine. */void MAIN_STATE_MACHINE(gn_rlp_f96_frame *frame, rlp_f96_header *header);/* This is the type we are just handling. */rlp_frame_types CurrentFrameType;/* Current state of RLP state machine. */rlp_state CurrentState=RLP_S0; /* We start at ADM and Detached *//* Next state of RLP state machine. */rlp_state NextState;/* Pointer to Send function that sends frame to phone. */bool (*RLP_SendFunction)(gn_rlp_f96_frame *frame, bool out_dtx);/* Pointer to Passup function which returns data/inds */int (*RLP_Passup)(rlp_user_inds ind, u8 *buffer, int length);/* State variables - see GSM 04.22, Annex A, section A.1.2 */rlp_state_variable UA_State;rlp_state_variable UI_State;rlp_state_variable Ackn_State;rlp_state_variable Poll_State;rlp_state_variable Poll_xchg;rlp_state_variable SABM_State;rlp_state_variable DISC_State;rlp_state_variable DM_State; /* FIXME - not handled */rlp_state_variable XI_R_State;rlp_state_variable XID_C_State;rlp_state_variable XID_R_State;rlp_state_variable TEST_R_State;u8 VR=0;u8 VA=0;u8 VS=0;u8 VD=0;u8 DISC_Count;u8 DTX_VR;rlp_frame_types DTX_SF;#define RLP_M 62rlp_data R[RLP_M];rlp_data S[RLP_M];rlp_state_variable SABM_State;int SABM_Count;rlp_user_request_store UserRequests;u8 Poll_Count = 0;/* For now timing is done based on a frame reception rate of 20ms *//* Serge has measured it as 18.4ms */#define RLP_T_Scaling 2/* Timers - a value of -1 means not set *//* To set, timer is loaded with RLP_Timeout1_Limit/RLP_T_Scaling. *//* Each received frame (including NULLS / errors) any >0 timer is decrease */int T;int T_RCVS[RLP_M];bool UA_FBit = true;bool Ackn_FBit = false;bool DM_FBit = false; /* FIXME - not handled */bool RRReady = false;bool LRReady = true; /* FIXME - not handled (as if we couldn't keep up with 9600bps :-) */bool DISC_PBit = false;u8 LastStatus = 0xff; /* Last Status byte *//* RLP Parameters. FIXME: Reset these - e.g. when entering state 0 */u8 RLP_SEND_WS = RLP_M-1;u8 RLP_RCV_WS = RLP_M-1;u8 RLP_Timeout1_Limit = 55;u8 RLP_N2 = 15; /* Maximum number of retransmisions. GSM spec says 6 here, but Nokia will XID this. */u8 RLP_T2 = 0;u8 RLP_VersionNumber = 0;/****** Externally called functions ********//*******************************************//* Function to initialise RLP code. Main purpose for now is to set the address of the RLP send function in the API code. */void rlp_initialise(bool (*rlp_send_function)(gn_rlp_f96_frame *frame, bool out_dtx), int (*rlp_passup)(rlp_user_inds ind, u8 *buffer, int length)){ int i; RLP_SendFunction = rlp_send_function; RLP_Passup = rlp_passup; UserRequests.Conn_Req = false; UserRequests.Attach_Req = false; UserRequests.Conn_Req_Neg = false; UserRequests.Reset_Resp = false; UserRequests.Disc_Req = false; CurrentState = RLP_S0; T = -1; for (i = 0; i < RLP_M; i++) T_RCVS[i] = -1; UA_FBit = true; Ackn_FBit = false; DISC_PBit = false; LastStatus = 0xff; Poll_Count = 0; VR = 0; VA = 0; VS = 0; VD = 0; RLP_SEND_WS = RLP_M-1; RLP_RCV_WS = RLP_M-1; RLP_Timeout1_Limit = 55; RLP_N2 = 15; RLP_T2 = 0; RLP_VersionNumber = 0;}/* Set a user event *//* Called by user program for now */void rlp_user_request_set(rlp_user_requests type, bool value){ switch (type) { case Conn_Req: UserRequests.Conn_Req = value; break; case Attach_Req: UserRequests.Attach_Req = value; break; case Conn_Req_Neg: UserRequests.Conn_Req_Neg = value; break; case Reset_Resp: UserRequests.Reset_Resp = value; break; case Disc_Req: UserRequests.Disc_Req = value; break; default: break; }}/***** Internal functions **********//***********************************//* Check whether a user event is set */bool rlp_user_request_get(rlp_user_requests type) { bool result = false, *x; switch (type) { case Conn_Req: x = &UserRequests.Conn_Req; break; case Attach_Req: x = &UserRequests.Attach_Req; break; case Conn_Req_Neg: x = &UserRequests.Conn_Req_Neg; break; case Reset_Resp: x = &UserRequests.Reset_Resp; break; case Disc_Req: x = &UserRequests.Disc_Req; break; default: x = &result; break; } result = *x; if (*x == true) *x = false; return result;}void RLP_SetTimer(int *timer){ *timer = (int)(RLP_Timeout1_Limit/RLP_T_Scaling);}/* Previous sequence number. */static INLINE u8 Decr(u8 x){ if (x == 0) return (RLP_M-1); else return (x-1);}/* Next sequence number. */static INLINE u8 Incr(u8 x){ if (x == RLP_M-1) return 0; else return (x+1);}/* Difference between sequence numbers. *//* FIXME: Not used now, so I have commented it out. PJ * static INLINE u8 Diff(u8 x, u8 y) * { * int result = x-y; * return (result >= 0) ? result : result + RLP_M; * }*//* Check value is within range */static bool InWindow(u8 val, u8 lower, u8 upper){ /* allow for one level of wrapping round */ if (lower >= RLP_M) lower -= RLP_M; if (upper >= RLP_M) upper -= RLP_M; if (val >= RLP_M) val -= RLP_M; /* .......L*****U....... */ if (lower <= upper) return (val >= lower) && (val <= upper); /* ******U.........L***** */ return (val <= upper) || (val >= lower);}void RLP_Init_link_vars(void){ int i; Ackn_State = _idle; Poll_State = _idle; Poll_Count = 0; Poll_xchg = _idle; SABM_State = _idle; DISC_State = _idle; RRReady = true; /* This seems a bit strange but it's what the spec says... */ VA = 0; VR = 0; VS = 0; VD = 0; LastStatus = 0xff; for (i = 0; i < RLP_M; i++) { R[i].State = _idle; S[i].State = _idle; }}void RLP_AddRingBufferDataToSlots(void){ u8 buffer[24]; int size; while ((S[VD].State == _idle) && ((size = RLP_Passup(GetData,buffer,24)) != 0)) { memset(S[VD].Data, 0xff, 25); /* FIXME - this isn't necessary - but makes debugging easier! */ if (size > 23) { S[VD].Data[0] = 0x1e; size = 24; } else S[VD].Data[0] = size; memcpy(&S[VD].Data[1], buffer, size); if (size != 24) S[VD].Data[size+1] = 0x1f; S[VD].State = _send; VD = Incr(VD); }}static void RLP_DumpF96Frame(gn_rlp_f96_frame *frame){ rlp_f96_header header; rlp_f96_header_decode(frame, &header); switch (header.Type) { case RLP_FT_U: /* Unnumbered frames. */ rlpprintf("Unnumbered Frame [$%02x%02x] M=%02x ", frame->Header[0], frame->Header[1], header.M); switch (header.M) { case RLP_U_SABM : rlpprintf("Set Asynchronous Balanced Mode (SABM) "); break; case RLP_U_UA: rlpprintf("Unnumbered Acknowledge (UA) "); break; case RLP_U_DISC: rlpprintf("Disconnect (DISC) "); break; case RLP_U_DM: rlpprintf("Disconnected Mode (DM) "); break; case RLP_U_UI: rlpprintf("Unnumbered Information (UI) "); break; case RLP_U_XID: rlpprintf("Exchange Information (XID) \n"); rlp_xid_display(frame->Data); break; case RLP_U_TEST: rlpprintf("Test (TEST) "); break; case RLP_U_NULL: rlpprintf("Null information (NULL) "); break; case RLP_U_REMAP: rlpprintf("Remap (REMAP) "); break; default: rlpprintf("Unknown!!! "); break; } break; case RLP_FT_S: /* Supervisory frames. */ rlpprintf("Supervisory Frame [$%02x%02x] S=0x%x N(R)=%d ", frame->Header[0], frame->Header[1], header.S, header.Nr); switch (header.S) { case RLP_S_RR: rlpprintf("RR"); break; case RLP_S_REJ: rlpprintf("REJ"); break; case RLP_S_RNR: rlpprintf("RNR"); break; case RLP_S_SREJ: rlpprintf("SREJ"); break; default: rlpprintf("BAD"); break; } break; default: rlpprintf("Info+Supervisory Frame [$%02x%02x] S=0x%x N(S)=%d N(R)=%d ", frame->Header[0], frame->Header[1], header.S, header.Ns, header.Nr); switch (header.S) { case RLP_S_RR: rlpprintf("RR"); break; case RLP_S_REJ: rlpprintf("REJ"); break; case RLP_S_RNR: rlpprintf("RNR"); break; case RLP_S_SREJ: rlpprintf("SREJ"); break; default: rlpprintf("BAD"); break; } break; } /* Command/Response and Poll/Final bits. */ rlpprintf(" C/R=%d P/F=%d", header.CR, header.PF); /* Information. */ /* if (CurrentFrameType != RLP_FT_U_NULL) { dprintf("\n"); for (count = 0; count < 25; count ++) { if (isprint(frame->Data[count])) dprintf("[%02x%c]", frame->Data[count], frame->Data[count]); else dprintf("[%02x ]", frame->Data[count]); if (count == 15) dprintf("\n"); } } */ /* FCS. */ rlpprintf(" FCS: %02x %02x %02x\n\n", frame->FCS[0], frame->FCS[1], frame->FCS[2]);}/* FIXME: Remove this after finishing. */void X(gn_rlp_f96_frame *frame){ int i; for (i = 0; i < 30; i++) dprintf("byte[%2d]: %02x\n", i, *( (u8 *)frame + i));}void ResetAllT_RCVS(void){ int i; for (i = 0; i < RLP_M; i++) T_RCVS[i] = -1;}/* This function is used for sending RLP frames to the phone. */void RLP_SendF96Frame(rlp_frame_types FrameType, bool OutCR, bool OutPF, u8 OutNR, u8 OutNS, u8 *OutData, u8 OutDTX){ gn_rlp_f96_frame frame; int i; frame.Header[0] = 0; frame.Header[1] = 0;#define SetCRBit frame.Header[0] |= 0x01;#define SetPFBit frame.Header[1] |= 0x02;#define ClearCRBit frame.Header[0] &= (~0x01);#define ClearPFBit frame.Header[1] &= (~0x02); /* If Command/Response bit is set, set it in the header. */ if (OutCR) SetCRBit; /* If Poll/Final bit is set, set it in the header. */ if (OutPF) SetPFBit; /* If OutData is not specified (ie. is NULL) we want to clear frame.Data array for the user. */ if (!OutData) { frame.Data[0] = 0x00; /* 0x1f */ for (i = 1; i < 25; i++) frame.Data[i] = 0; } else { for (i = 0; i < 25; i++) frame.Data[i] = OutData[i]; }#define PackM(x) frame.Header[1] |= ((x) << 2);#define PackS(x) frame.Header[0]|=((x) << 1);#define PackNR frame.Header[1] |= (OutNR << 2);#define PackNS frame.Header[0] |= (OutNS << 3); frame.Header[1] |= (OutNS >> 5); switch (FrameType) { /* Unnumbered frames. Be careful - some commands are used as commands only, so we have to set C/R bit later. We should not allow user for example to send SABM as response because in the spec is: The SABM encoding is used as command only. */ case RLP_FT_U_SABM: frame.Header[0] |= 0xf8; /* See page 11 of the GSM 04.22 spec - 0 X X 1 1 1 1 1 */ frame.Header[1] |= 0x01; /* 1 P/F M1 M2 M3 M4 M5 X */ SetCRBit; /* The SABM encoding is used as a command only. */ SetPFBit; /* It is always used with the P-bit set to "1". */ PackM(RLP_U_SABM); break; case RLP_FT_U_UA: frame.Header[0] |= 0xf8; frame.Header[1] |= 0x01; ClearCRBit; /* The UA encoding is used as a response only. */ PackM(RLP_U_UA); break; case RLP_FT_U_DISC: frame.Header[0] |= 0xf8; frame.Header[1] |= 0x01; SetCRBit; /* The DISC encoding is used as a command only. */ PackM(RLP_U_DISC); break; case RLP_FT_U_DM: frame.Header[0] |= 0xf8; frame.Header[1] |= 0x01; ClearCRBit; /* The DM encoding is used as a response only. */ PackM(RLP_U_DM); break; case RLP_FT_U_NULL: frame.Header[0] |= 0xf8; frame.Header[1] |= 0x01; PackM(RLP_U_NULL); break; case RLP_FT_U_UI: frame.Header[0] |= 0xf8; frame.Header[1] |= 0x01; PackM(RLP_U_UI); break; case RLP_FT_U_XID: frame.Header[0] |= 0xf8; frame.Header[1] |= 0x01; SetPFBit; /* XID frames are always used with the P/F-bit set to "1". */ PackM(RLP_U_XID); break; case RLP_FT_U_TEST:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -