1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.nfc.dhimpl;
18
19import com.android.nfc.DeviceHost;
20import com.android.nfc.LlcpException;
21
22import android.annotation.SdkConstant;
23import android.annotation.SdkConstant.SdkConstantType;
24import android.content.Context;
25import android.content.SharedPreferences;
26import android.nfc.ErrorCodes;
27import android.nfc.tech.Ndef;
28import android.nfc.tech.TagTechnology;
29import android.util.Log;
30import com.android.nfc.NfcDiscoveryParameters;
31
32import java.io.File;
33
34/**
35 * Native interface to the NFC Manager functions
36 */
37public class NativeNfcManager implements DeviceHost {
38    private static final String TAG = "NativeNfcManager";
39
40    private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so";
41
42    static final String PREF = "NxpDeviceHost";
43
44    private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime";
45    private static final long FIRMWARE_MODTIME_DEFAULT = -1;
46
47    static final String DRIVER_NAME = "nxp";
48
49    static final int DEFAULT_LLCP_MIU = 128;
50    static final int DEFAULT_LLCP_RWSIZE = 1;
51
52    static {
53        System.loadLibrary("nfc_jni");
54    }
55
56    /* Native structure */
57    private long mNative;
58
59    private final DeviceHostListener mListener;
60    private final Context mContext;
61
62    public NativeNfcManager(Context context, DeviceHostListener listener) {
63        mListener = listener;
64        initializeNativeStructure();
65        mContext = context;
66    }
67
68    public native boolean initializeNativeStructure();
69
70    private native boolean doDownload();
71
72    public native int doGetLastError();
73
74    @Override
75    public void checkFirmware() {
76        // Check that the NFC controller firmware is up to date.  This
77        // ensures that firmware updates are applied in a timely fashion,
78        // and makes it much less likely that the user will have to wait
79        // for a firmware download when they enable NFC in the settings
80        // app.  Firmware download can take some time, so this should be
81        // run in a separate thread.
82
83        // check the timestamp of the firmware file
84        File firmwareFile;
85        int nbRetry = 0;
86        try {
87            firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME);
88        } catch(NullPointerException npe) {
89            Log.e(TAG,"path to firmware file was null");
90            return;
91        }
92
93        long modtime = firmwareFile.lastModified();
94
95        SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
96        long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT);
97        Log.d(TAG,"prev modtime: " + prev_fw_modtime);
98        Log.d(TAG,"new modtime: " + modtime);
99        if (prev_fw_modtime == modtime) {
100            return;
101        }
102
103        // FW download.
104        while(nbRetry < 5) {
105            Log.d(TAG,"Perform Download");
106            if(doDownload()) {
107                Log.d(TAG,"Download Success");
108                // Now that we've finished updating the firmware, save the new modtime.
109                prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply();
110                break;
111            } else {
112                Log.d(TAG,"Download Failed");
113                nbRetry++;
114            }
115        }
116    }
117
118    private native boolean doInitialize();
119
120    @Override
121    public boolean initialize() {
122        return doInitialize();
123    }
124
125    private native boolean doDeinitialize();
126
127    @Override
128    public boolean deinitialize() {
129        return doDeinitialize();
130    }
131
132    @Override
133    public String getName() {
134        return DRIVER_NAME;
135    }
136
137    @Override
138    public boolean sendRawFrame(byte[] data)
139    {
140        return false;
141    }
142
143    @Override
144    public boolean routeAid(byte[] aid, int route)
145    {
146        return false;
147    }
148
149    @Override
150    public boolean unrouteAid(byte[] aid)
151    {
152       return false;
153    }
154
155    @Override
156    public boolean commitRouting()
157    {
158        return false;
159    }
160
161    private native void doEnableDiscovery(int techMask,
162                                          boolean enableLowPowerPolling,
163                                          boolean enableReaderMode,
164                                          boolean restart);
165    @Override
166    public void enableDiscovery(NfcDiscoveryParameters params, boolean restart) {
167        doEnableDiscovery(params.getTechMask(), params.shouldEnableLowPowerDiscovery(),
168                params.shouldEnableReaderMode(), restart);
169    }
170
171    @Override
172    public native void disableDiscovery();
173
174    private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap,
175            String sn);
176
177    @Override
178    public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn)
179            throws LlcpException {
180        LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn);
181        if (socket != null) {
182            return socket;
183        } else {
184            /* Get Error Status */
185            int error = doGetLastError();
186
187            Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
188
189            switch (error) {
190                case ErrorCodes.ERROR_BUFFER_TO_SMALL:
191                case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
192                    throw new LlcpException(error);
193                default:
194                    throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
195            }
196        }
197    }
198
199    private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu,
200            int rw, int linearBufferLength);
201    @Override
202    public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu,
203            int rw, int linearBufferLength) throws LlcpException {
204        LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength);
205        if (socket != null) {
206            return socket;
207        } else {
208            /* Get Error Status */
209            int error = doGetLastError();
210
211            Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
212
213            switch (error) {
214                case ErrorCodes.ERROR_BUFFER_TO_SMALL:
215                case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
216                    throw new LlcpException(error);
217                default:
218                    throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
219            }
220        }
221    }
222
223    private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw,
224            int linearBufferLength);
225    @Override
226    public LlcpSocket createLlcpSocket(int sap, int miu, int rw,
227            int linearBufferLength) throws LlcpException {
228        LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength);
229        if (socket != null) {
230            return socket;
231        } else {
232            /* Get Error Status */
233            int error = doGetLastError();
234
235            Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
236
237            switch (error) {
238                case ErrorCodes.ERROR_BUFFER_TO_SMALL:
239                case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
240                    throw new LlcpException(error);
241                default:
242                    throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
243            }
244        }
245    }
246
247    @Override
248    public native boolean doCheckLlcp();
249
250    @Override
251    public native boolean doActivateLlcp();
252
253    private native void doResetTimeouts();
254
255    @Override
256    public void resetTimeouts() {
257        doResetTimeouts();
258    }
259
260    @Override
261    public native void doAbort();
262
263    private native boolean doSetTimeout(int tech, int timeout);
264    @Override
265    public boolean setTimeout(int tech, int timeout) {
266        return doSetTimeout(tech, timeout);
267    }
268
269    private native int doGetTimeout(int tech);
270    @Override
271    public int getTimeout(int tech) {
272        return doGetTimeout(tech);
273    }
274
275
276    @Override
277    public boolean canMakeReadOnly(int ndefType) {
278        return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 ||
279                ndefType == Ndef.TYPE_MIFARE_CLASSIC);
280    }
281
282    @Override
283    public int getMaxTransceiveLength(int technology) {
284        switch (technology) {
285            case (TagTechnology.NFC_A):
286            case (TagTechnology.MIFARE_CLASSIC):
287            case (TagTechnology.MIFARE_ULTRALIGHT):
288                return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
289            case (TagTechnology.NFC_B):
290                return 0; // PN544 does not support transceive of raw NfcB
291            case (TagTechnology.NFC_V):
292                return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
293            case (TagTechnology.ISO_DEP):
294                /* The maximum length of a normal IsoDep frame consists of:
295                 * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes
296                 * such a frame is supported. Extended length frames however
297                 * are not supported.
298                 */
299                return 261; // Will be automatically split in two frames on the RF layer
300            case (TagTechnology.NFC_F):
301                return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC
302            default:
303                return 0;
304        }
305
306    }
307
308    private native void doSetP2pInitiatorModes(int modes);
309    @Override
310    public void setP2pInitiatorModes(int modes) {
311        doSetP2pInitiatorModes(modes);
312    }
313
314    private native void doSetP2pTargetModes(int modes);
315    @Override
316    public void setP2pTargetModes(int modes) {
317        doSetP2pTargetModes(modes);
318    }
319
320    @Override
321    public boolean enableScreenOffSuspend() {
322        // Snooze mode not supported on NXP silicon
323        Log.i(TAG, "Snooze mode is not supported on NXP NFCC");
324        return false;
325    }
326
327    @Override
328    public boolean disableScreenOffSuspend() {
329        // Snooze mode not supported on NXP silicon
330        Log.i(TAG, "Snooze mode is not supported on NXP NFCC");
331        return true;
332    }
333
334    @Override
335    public boolean getExtendedLengthApdusSupported() {
336        // Not supported on the PN544
337        return false;
338    }
339
340    @Override
341    public int getDefaultLlcpMiu() {
342        return DEFAULT_LLCP_MIU;
343    }
344
345    @Override
346    public int getDefaultLlcpRwSize() {
347        return DEFAULT_LLCP_RWSIZE;
348    }
349
350    private native String doDump();
351    @Override
352    public String dump() {
353        return doDump();
354    }
355
356    /**
357     * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered)
358     */
359    private void notifyNdefMessageListeners(NativeNfcTag tag) {
360        mListener.onRemoteEndpointDiscovered(tag);
361    }
362
363    /**
364     * Notifies P2P Device detected, to activate LLCP link
365     */
366    private void notifyLlcpLinkActivation(NativeP2pDevice device) {
367        mListener.onLlcpLinkActivated(device);
368    }
369
370    /**
371     * Notifies P2P Device detected, to activate LLCP link
372     */
373    private void notifyLlcpLinkDeactivated(NativeP2pDevice device) {
374        mListener.onLlcpLinkDeactivated(device);
375    }
376
377    private void notifyRfFieldActivated() {
378        mListener.onRemoteFieldActivated();
379    }
380
381    private void notifyRfFieldDeactivated() {
382        mListener.onRemoteFieldDeactivated();
383    }
384}
385