update pi GPIO pin restrictions
parent
12eebc9f44
commit
d2ae4ff300
|
@ -1,5 +1,7 @@
|
|||
class PinBinding < ApplicationRecord
|
||||
OFF_LIMITS = [ 6, 12, 13, 17, 21, 23, 24, 25, 27 ]
|
||||
OFF_LIMITS = [
|
||||
2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 19, 21, 23, 24, 25, 27
|
||||
]
|
||||
BAD_PIN_NUM = \
|
||||
"The following pin numbers cannot be used: %s" % OFF_LIMITS.join(", ")
|
||||
|
||||
|
@ -20,7 +22,7 @@ class PinBinding < ApplicationRecord
|
|||
end
|
||||
|
||||
def random_pin_num
|
||||
[*(0..69)]
|
||||
[*(0..27)]
|
||||
.without(*OFF_LIMITS)
|
||||
.without(*device.pin_bindings.pluck(:pin_num))
|
||||
.sample
|
||||
|
|
|
@ -11,12 +11,16 @@ describe("sortByNameAndPin()", () => {
|
|||
const btn1Pin = ButtonPin.estop;
|
||||
const btn2Pin = ButtonPin.unlock;
|
||||
|
||||
const GPIO_SM = 4;
|
||||
const GPIO_LG = 18;
|
||||
|
||||
const sortTest = (first: number, second: number, order: Order) =>
|
||||
expect(sortByNameAndPin(first, second)).toEqual(order);
|
||||
|
||||
it("sorts", () => {
|
||||
sortTest(btn1Pin, 10, Order.firstSmaller); // Button 1 < GPIO 10
|
||||
sortTest(2, 10, Order.firstSmaller); // GPIO 2 < GPIO 10
|
||||
sortTest(btn1Pin, 1, Order.firstSmaller); // Button 1 < GPIO 1
|
||||
sortTest(GPIO_SM, GPIO_LG, Order.firstSmaller); // GPIO SM < GPIO LG
|
||||
sortTest(GPIO_LG, GPIO_SM, Order.secondSmaller); // GPIO LG > GPIO SM
|
||||
sortTest(btn1Pin, btn2Pin, Order.firstSmaller); // Button 1 < Button 2
|
||||
sortTest(btn2Pin, btn1Pin, Order.secondSmaller); // Button 2 > Button 1
|
||||
sortTest(1, 1, Order.equal); // GPIO 1 == GPIO 1
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
const mockDevice = {
|
||||
registerGpio: jest.fn(() => { return Promise.resolve(); }),
|
||||
unregisterGpio: jest.fn(() => { return Promise.resolve(); }),
|
||||
registerGpio: jest.fn(() => Promise.resolve()),
|
||||
unregisterGpio: jest.fn(() => Promise.resolve()),
|
||||
};
|
||||
jest.mock("../../../device", () => ({
|
||||
getDevice: () => (mockDevice)
|
||||
}));
|
||||
jest.mock("../../../device", () => ({ getDevice: () => mockDevice }));
|
||||
|
||||
jest.mock("../../../api/crud", () => ({
|
||||
initSave: jest.fn()
|
||||
}));
|
||||
jest.mock("../../../api/crud", () => ({ initSave: jest.fn() }));
|
||||
|
||||
import * as React from "react";
|
||||
import { mount, shallow } from "enzyme";
|
||||
|
@ -33,6 +29,8 @@ import {
|
|||
} from "farmbot/dist/resources/api_resources";
|
||||
import { error, warning } from "../../../toast/toast";
|
||||
|
||||
const AVAILABLE_PIN = 18;
|
||||
|
||||
describe("<PinBindingInputGroup/>", () => {
|
||||
function fakeProps(): PinBindingInputGroupProps {
|
||||
const fakeResources: TaggedSequence[] = [fakeSequence(), fakeSequence()];
|
||||
|
@ -43,8 +41,8 @@ describe("<PinBindingInputGroup/>", () => {
|
|||
const resources = buildResourceIndex(fakeResources).index;
|
||||
return {
|
||||
pinBindings: [
|
||||
{ pin_number: 10, sequence_id: 1 },
|
||||
{ pin_number: 11, sequence_id: 2 },
|
||||
{ pin_number: 4, sequence_id: 1 },
|
||||
{ pin_number: 5, sequence_id: 2 },
|
||||
],
|
||||
dispatch: jest.fn(),
|
||||
resources: resources,
|
||||
|
@ -69,7 +67,7 @@ describe("<PinBindingInputGroup/>", () => {
|
|||
const wrapper = mount(<PinBindingInputGroup {...fakeProps()} />);
|
||||
const buttons = wrapper.find("button");
|
||||
expect(buttons.last().text()).toEqual("BIND");
|
||||
wrapper.setState({ pinNumberInput: 7 });
|
||||
wrapper.setState({ pinNumberInput: AVAILABLE_PIN });
|
||||
buttons.last().simulate("click");
|
||||
expect(error).toHaveBeenCalledWith("Please select a sequence or action.");
|
||||
});
|
||||
|
@ -98,7 +96,7 @@ describe("<PinBindingInputGroup/>", () => {
|
|||
const buttons = wrapper.find("button");
|
||||
expect(buttons.last().text()).toEqual("BIND");
|
||||
wrapper.setState({
|
||||
pinNumberInput: 2,
|
||||
pinNumberInput: 0,
|
||||
bindingType: PinBindingType.special,
|
||||
sequenceIdInput: undefined,
|
||||
specialActionInput: PinBindingSpecialAction.emergency_lock
|
||||
|
@ -107,7 +105,7 @@ describe("<PinBindingInputGroup/>", () => {
|
|||
expect(mockDevice.registerGpio).not.toHaveBeenCalled();
|
||||
expect(initSave).toHaveBeenCalledWith("PinBinding",
|
||||
{
|
||||
pin_num: 2,
|
||||
pin_num: 0,
|
||||
binding_type: PinBindingType.special,
|
||||
special_action: PinBindingSpecialAction.emergency_lock
|
||||
});
|
||||
|
@ -125,15 +123,16 @@ describe("<PinBindingInputGroup/>", () => {
|
|||
});
|
||||
|
||||
it("sets pin", () => {
|
||||
const wrapper = mount<PinBindingInputGroup>(<PinBindingInputGroup
|
||||
{...fakeProps()} />);
|
||||
const p = fakeProps();
|
||||
const wrapper = mount<PinBindingInputGroup>(<PinBindingInputGroup {...p} />);
|
||||
expect(wrapper.instance().state.pinNumberInput).toEqual(undefined);
|
||||
wrapper.instance().setSelectedPin(10); // pin already bound
|
||||
const { pin_number } = p.pinBindings[0];
|
||||
wrapper.instance().setSelectedPin(pin_number); // pin already bound
|
||||
expect(wrapper.instance().state.pinNumberInput).toEqual(undefined);
|
||||
wrapper.instance().setSelectedPin(99); // invalid pin
|
||||
expect(wrapper.instance().state.pinNumberInput).toEqual(undefined);
|
||||
wrapper.instance().setSelectedPin(5); // available pin
|
||||
expect(wrapper.instance().state.pinNumberInput).toEqual(5);
|
||||
wrapper.instance().setSelectedPin(AVAILABLE_PIN); // available pin
|
||||
expect(wrapper.instance().state.pinNumberInput).toEqual(AVAILABLE_PIN);
|
||||
wrapper.instance().setSelectedPin(1); // reserved pin
|
||||
expect(wrapper.instance().state.pinNumberInput).toEqual(1);
|
||||
expect(warning).toHaveBeenCalledWith(
|
||||
|
@ -144,8 +143,8 @@ describe("<PinBindingInputGroup/>", () => {
|
|||
const wrapper = shallow<PinBindingInputGroup>(<PinBindingInputGroup
|
||||
{...fakeProps()} />);
|
||||
expect(wrapper.instance().state.pinNumberInput).toEqual(undefined);
|
||||
wrapper.instance().setSelectedPin(7);
|
||||
expect(wrapper.instance().state.pinNumberInput).toEqual(7);
|
||||
wrapper.instance().setSelectedPin(AVAILABLE_PIN);
|
||||
expect(wrapper.instance().state.pinNumberInput).toEqual(AVAILABLE_PIN);
|
||||
});
|
||||
|
||||
it("changes binding type", () => {
|
||||
|
@ -177,8 +176,10 @@ describe("<PinNumberInputGroup />", () => {
|
|||
pinNumberInput={undefined}
|
||||
boundPins={[]}
|
||||
setSelectedPin={setSelectedPin} />);
|
||||
wrapper.find("FBSelect").simulate("change", { label: "", value: 7 });
|
||||
expect(setSelectedPin).toHaveBeenCalledWith(7);
|
||||
wrapper.find("FBSelect").simulate("change", {
|
||||
label: "", value: AVAILABLE_PIN
|
||||
});
|
||||
expect(setSelectedPin).toHaveBeenCalledWith(AVAILABLE_PIN);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -207,7 +208,7 @@ describe("<ActionTargetDropDown />", () => {
|
|||
});
|
||||
|
||||
describe("<SequenceTargetDropDown />", () => {
|
||||
it("sets action", () => {
|
||||
it("sets sequence ID", () => {
|
||||
const setSequenceIdInput = jest.fn();
|
||||
const wrapper = shallow(<SequenceTargetDropDown
|
||||
sequenceIdInput={undefined}
|
||||
|
|
|
@ -1,18 +1,14 @@
|
|||
const mockDevice = {
|
||||
registerGpio: jest.fn(() => Promise.resolve()),
|
||||
unregisterGpio: jest.fn(() => Promise.resolve()),
|
||||
};
|
||||
jest.mock("../../../device", () => ({ getDevice: () => mockDevice }));
|
||||
|
||||
jest.mock("../../../api/crud", () => ({ destroy: jest.fn() }));
|
||||
|
||||
import {
|
||||
PinBindingType, PinBindingSpecialAction
|
||||
} from "farmbot/dist/resources/api_resources";
|
||||
const mockDevice = {
|
||||
registerGpio: jest.fn(() => { return Promise.resolve(); }),
|
||||
unregisterGpio: jest.fn(() => { return Promise.resolve(); }),
|
||||
};
|
||||
jest.mock("../../../device", () => ({
|
||||
getDevice: () => (mockDevice)
|
||||
}));
|
||||
|
||||
jest.mock("../../../api/crud", () => ({
|
||||
destroy: jest.fn()
|
||||
}));
|
||||
|
||||
const mockData = [{
|
||||
pin_number: 1, sequence_id: undefined,
|
||||
special_action: PinBindingSpecialAction.sync,
|
||||
|
|
|
@ -4,13 +4,11 @@ import { RpiGpioDiagram, RpiGpioDiagramProps } from "../rpi_gpio_diagram";
|
|||
import { Color } from "../../../ui/index";
|
||||
|
||||
describe("<RpiGpioDiagram />", () => {
|
||||
function fakeProps(): RpiGpioDiagramProps {
|
||||
return {
|
||||
boundPins: [27],
|
||||
setSelectedPin: jest.fn(),
|
||||
selectedPin: undefined
|
||||
};
|
||||
}
|
||||
const fakeProps = (): RpiGpioDiagramProps => ({
|
||||
boundPins: [27],
|
||||
setSelectedPin: jest.fn(),
|
||||
selectedPin: undefined
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
const wrapper = mount(<RpiGpioDiagram {...fakeProps()} />);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
import {
|
||||
PinBindingType,
|
||||
PinBindingSpecialAction
|
||||
|
@ -61,9 +60,16 @@ enum LEDPin {
|
|||
|
||||
/** Other pins used by FarmBot OS that cannot be used in pin bindings. */
|
||||
enum SystemPins {
|
||||
sda = 2,
|
||||
scl = 3,
|
||||
reset = 19,
|
||||
i2c1_sda = 2,
|
||||
i2c1_scl = 3,
|
||||
spi0_ce1 = 7,
|
||||
spi0_ce0 = 8,
|
||||
spi0_miso = 9,
|
||||
spi0_mosi = 10,
|
||||
spi0_sclk = 11,
|
||||
uart_tx = 14,
|
||||
uart_rx = 15,
|
||||
reset_2560 = 19,
|
||||
}
|
||||
|
||||
const toPinNum = (n: string) => parseInt(n);
|
||||
|
@ -73,9 +79,11 @@ const otherSysBindings: number[] = Object.values(SystemPins).map(toPinNum);
|
|||
/** All pin numbers used by FarmBot OS that cannot be used in pin bindings. */
|
||||
export const sysBindings = sysLedBindings.concat(sysBtnBindings, otherSysBindings);
|
||||
|
||||
const piI2cPins = [0, 1];
|
||||
const piI2c0Pins = [0, 1];
|
||||
export const piSpi0Pins = [7, 8, 9, 10, 11];
|
||||
export const piSpi1Pins = [16, 17, 18, 19, 20, 21];
|
||||
/** Pin numbers used for special purposes by the RPi. (internal pullup, etc.) */
|
||||
export const reservedPiGPIO = piI2cPins;
|
||||
export const reservedPiGPIO = piI2c0Pins;
|
||||
|
||||
const LabeledGpioPins: { [x: number]: string } = {
|
||||
[ButtonPin.estop]: "Button 1: E-STOP",
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import * as React from "react";
|
||||
|
||||
import { Row, Col, FBSelect, NULL_CHOICE, DropDownItem } from "../../ui";
|
||||
import { PinBindingColWidth } from "./pin_bindings";
|
||||
import { Popover, Position } from "@blueprintjs/core";
|
||||
|
|
|
@ -36,7 +36,7 @@ describe Api::PinBindingsController do
|
|||
it 'creates a pin binding' do
|
||||
sign_in user
|
||||
s = FakeSequence.create( device: device)
|
||||
input = { pin_num: 10, sequence_id: s.id}
|
||||
input = { pin_num: 4, sequence_id: s.id}
|
||||
b4 = PinBinding.count
|
||||
post :create, body: input.to_json, params: { format: :json}
|
||||
expect(response.status).to eq(200)
|
||||
|
|
|
@ -64,7 +64,7 @@ describe Api::SequencesController do
|
|||
sign_in user
|
||||
pb = PinBindings::Create.run!(device: user.device,
|
||||
sequence_id: sequence.id,
|
||||
pin_num: 10)
|
||||
pin_num: 4)
|
||||
delete :destroy, params: { id: sequence.id }
|
||||
expect(response.status).to eq(422)
|
||||
expect(json[:sequence]).to include("in use")
|
||||
|
|
Loading…
Reference in New Issue