All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.oracle.dio.i2cbus.impl.I2CSlaveImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.oracle.dio.i2cbus.impl;

import java.io.IOException;
import java.nio.*;
import java.security.AccessController;
import java.util.LinkedList;
import java.util.List;

import com.oracle.dio.power.impl.PowerManagedBase;
import com.oracle.dio.utils.Constants;
import com.oracle.dio.utils.ExceptionMessage;
import com.oracle.dio.utils.Logging;

import jdk.dio.*;
import jdk.dio.i2cbus.*;
import jdk.dio.i2cbus.I2CDevice.Bus;

import romizer.*;

class I2CSlaveImpl extends PowerManagedBase implements I2CDevice {

    static final int I2C_REGULAR = 0;
    static final int I2C_COMBINED_START = 1;
    static final int I2C_COMBINED_END = 2;
    static final int I2C_COMBINED_BODY = 3;

    I2CSlaveImpl(DeviceDescriptor dscr, int mode) throws
            DeviceNotFoundException, InvalidDeviceConfigException {
        super(dscr, mode);

        I2CPermission permission = new I2CPermission(getSecurityName());
        AccessController.checkPermission(permission);

        I2CDeviceConfig cfg = dscr.getConfiguration();

        if (cfg.getControllerName() != null) {
            throw new InvalidDeviceConfigException(
                    ExceptionMessage.format(ExceptionMessage.DEVICE_OPEN_WITH_DEVICENAME_UNSUPPORTED)
            );
        }

        open0(cfg, mode == DeviceManager.EXCLUSIVE);

        initPowerManagement();
    }

    public Bus getBus() throws IOException {
        return new Bus() {
            public jdk.dio.i2cbus.I2CCombinedMessage createCombinedMessage() {
                return new I2CCombinedMessage();
            }
        };
    }

    private String getSecurityName() {
        I2CDeviceConfig cfg = dscr.getConfiguration();
        String securityName = (DeviceConfig.DEFAULT == cfg.getControllerNumber()) ?
                "" : String.valueOf(cfg.getControllerNumber());
        securityName = (DeviceConfig.DEFAULT == cfg.getAddress()) ?
                securityName : securityName + ":" + cfg.getAddress();
        return securityName;
    }

    protected void checkPowerPermission() {
        AccessController.checkPermission(new I2CPermission(getSecurityName(),
                DevicePermission.POWER_MANAGE));
    }

    private void doCheck(int skip, ByteBuffer buf) {
        if (buf == null)
            throw new NullPointerException();

        if (skip < 0)
            throw new IllegalArgumentException();
    }

    @Override
    public ByteBuffer getInputBuffer() throws ClosedDeviceException,
            IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public ByteBuffer getOutputBuffer() throws ClosedDeviceException,
            IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public int read() throws IOException,
            UnavailableDeviceException, ClosedDeviceException {
        ByteBuffer dst = ByteBuffer.allocateDirect(1);
        read(dst);
        return dst.get(0);
    }

    @Override
    public int read(ByteBuffer dst) throws IOException,
            UnavailableDeviceException, ClosedDeviceException {
        return read(0, dst);
    }

    @Override
    public int read(int skip, ByteBuffer dst) throws IOException,
            UnavailableDeviceException, ClosedDeviceException {

        doCheck(skip, dst);

        return transfer(I2C_REGULAR, skip, dst);
    }

    @Override
    public int read(int subaddress, int subaddressSize,
                    ByteBuffer dst) throws IOException, UnavailableDeviceException,
            ClosedDeviceException {
        return read(subaddress, subaddressSize, 0, dst);
    }

    @Override
    public int read(int subaddress, int subaddressSize, int skip,
                    ByteBuffer dst) throws IOException, UnavailableDeviceException,
            ClosedDeviceException {

        if (subaddressSize <= 0 || subaddressSize > 4 || subaddress < 0)
            throw new IllegalArgumentException();

        doCheck(skip, dst);

        ByteBuffer tmp = ByteBuffer.wrap(new byte[4/*sizeof(int)*/]);
        tmp.order(ByteOrder.BIG_ENDIAN);
        tmp.putInt(subaddress);
        tmp.position(4 - subaddressSize);
        I2CCombinedMessage msg = new I2CCombinedMessage();
        msg.appendWrite(this, tmp);
        msg.appendRead(this, skip, dst);
        return msg.transfer()[0];
    }

    @Override
    public int write(ByteBuffer src) throws IOException,
            UnavailableDeviceException, ClosedDeviceException {
        doCheck(0, src);
        return transfer(I2C_REGULAR, -1, src);
    }


    @Override
    public void write(int srcData) throws IOException,
            UnavailableDeviceException, ClosedDeviceException {
        ByteBuffer dst = ByteBuffer.allocateDirect(1);
        dst.put((byte) srcData);
        dst.flip();
        write(dst);
    }

    @Override
    public int write(int subaddress, int subaddressSize,
                     ByteBuffer src) throws IOException, UnavailableDeviceException,
            ClosedDeviceException {
        boolean callEnd = false;

        if (subaddressSize <= 0 || subaddressSize > 4 || subaddress < 0) {
            throw new IllegalArgumentException();
        }

        doCheck(0, src);

        ByteBuffer tmp = ByteBuffer.allocateDirect(4/*size of int*/ + src.remaining());
        tmp.order(ByteOrder.BIG_ENDIAN);
        tmp.putInt(subaddress);
        tmp.put(src);
        tmp.position(4 - subaddressSize);
        return write(tmp) - subaddressSize;
    }

    /**
     * @throws IllegalStateException if the bus is occupied for
     *                               communication with other peripheral or with other
     *                               transaction
     */
    int transfer(int flag, int skip, ByteBuffer appBuffer) throws
            UnavailableDeviceException, ClosedDeviceException, IOException {
        int ret = 0;

        if (!appBuffer.hasRemaining() && skip <= 0) {
            return 0;
        }

        ByteBuffer direct = toDirect(skip, appBuffer);

        checkPowerState();
        // if driver supports combined message
        // synchronized block introduce small since {@code transfer0} returns
        // immediately if single shot is trying to interrupt ongoing I2C combined
        // message.
        // if not, then it is pipelining transfer request.
        synchronized (handle) {
            try {
                conditionalLock();
                ret = transfer0(skip < 0, direct, flag);
            } finally {
                conditionalUnlock();
            }
        }

        direct.limit(ret);

        if (skip > 0) {
            ret = (ret > skip) ? ret - skip : 0;
        }

        BuffersMap conversion = new BuffersMap(skip, appBuffer, ret, direct);

        return flag == I2CSlaveImpl.I2C_REGULAR ?
                restoreFromDirect(conversion) :
                addDelayedConversion(conversion);
    }

    static class BuffersMap {
        int skip, ret;
        ByteBuffer direct, nonDirect;

        BuffersMap(int skip, ByteBuffer nonDirect, int ret, ByteBuffer direct) {
            this.skip = skip;
            this.ret = ret;
            this.direct = direct;
            this.nonDirect = nonDirect;
        }
    }

    private List delayedConversions = new LinkedList();

    private int addDelayedConversion(BuffersMap conversion) {
        delayedConversions.add(conversion);
        return conversion.ret;
    }

    void applyDelayedConversions() {
        for (BuffersMap delayedConversion : delayedConversions) {
            restoreFromDirect(delayedConversion);
        }

        delayedConversions.clear();
    }

    private int restoreFromDirect(BuffersMap conversion) {
        ByteBuffer toSend = conversion.direct;
        int ret = conversion.ret;
        int skip = conversion.skip;
        ByteBuffer buf = conversion.nonDirect;

        if (skip > 0) {
            if (ret > 0) {
                // need to count only bytes transfered to recv buffer
                toSend.position(skip);
                try {
                    buf.put(toSend);
                } catch (IllegalArgumentException e) {
                    // application do something with ByteBuffer that affects its
                    // postion() and limit() in such a way that setting new
                    // position throws IllegalArgumentException
                    Logging.reportError(ExceptionMessage.format(ExceptionMessage.BUFFER_IS_MODIFIED));
                }
            }
        } else {
            try {
                // if write just update buffer position
                if (skip < 0) {
                    buf.position(buf.position() + ret);
                } else {
                    // slight overhead if buf and toSend point to the same memory area
                    buf.put(toSend);
                }
            } catch (IllegalArgumentException e) {
                // application do something with ByteBuffer that affects its
                // postion() and limit() in such a way that setting new
                // position throws IllegalArgumentException
                Logging.reportError(ExceptionMessage.format(ExceptionMessage.BUFFER_IS_MODIFIED));
            }
        }

        return ret;
    }

    private ByteBuffer toDirect(int skip, ByteBuffer buf) {
        ByteBuffer toSend;
        if (skip > 0) {
            toSend = ByteBuffer.allocateDirect(buf.remaining() + skip);
        } else {
            toSend = convert(buf, null);
        }
        return toSend;
    }

    protected synchronized int getGrpID() {
        return getGrpID0();
    }

    @Override
    public ByteBuffer prepareBuffer(ByteBuffer buffer, int size) throws IOException, ClosedDeviceException {
        return (ByteBuffer) super.prepareBufferInt(buffer, size);
    }

    @Local(DontRemoveFields = {
            "jdk.dio.i2cbus.I2CDeviceConfig.controllerNumber",
            "jdk.dio.i2cbus.I2CDeviceConfig.clockFrequency",
            "jdk.dio.i2cbus.I2CDeviceConfig.addressSize",
            "jdk.dio.i2cbus.I2CDeviceConfig.address",
            "com.oracle.dio.impl.Handle.unlock_func_ptr",
            "com.oracle.dio.impl.Handle.native_handle",
            "com.oracle.dio.impl.Handle.lock_func_ptr",
            "com.oracle.dio.impl.Handle.close_func_ptr",
            "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native void open0(Object config, boolean isExclusive);

    /**
     * Transfers data from {@code dst} buffer over I2C bus. The
     * direction of transfer is set by {@code skip} value
     *
     * @param flag  type of message: REGULAR, COMBINED_START ...
     *              COMBINED_END
     * @param write direction of transfer, {@code true} for write,
     *              {@code false} for read
     * @param dst   the buffer that holds the data or to store data
     *              to.
     * @return number of bytes was transfered over the bus.
     */
    @Local(DontRemoveFields = {
            "java.nio.Buffer.position",
            "java.nio.Buffer.limit",
            "java.nio.Buffer.flags",
            "java.nio.Buffer.data",
            "java.nio.Buffer.arrayOffset",
            "com.oracle.dio.impl.Handle.native_handle",
            "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native int transfer0(boolean write, ByteBuffer dst, int flag);

    @Local(DontRemoveFields = {
            "com.oracle.dio.impl.Handle.native_handle",
            "com.oracle.dio.impl.AbstractPeripheral.handle",
    })
    private native int getGrpID0();
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy