ModelEditor.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "ModelEditor.h" | ||
| 2 | |||
| 3 | 22 | edit_changes_t editChanges(model_edit_type_t type, const edit_result_t &result) { | |
| 4 | 22 | edit_changes_t c; | |
| 5 | 22 | switch(type) { | |
| 6 | 6 | case model_edit_type_t::add_shade: | |
| 7 | case model_edit_type_t::save_shade: | ||
| 8 | case model_edit_type_t::set_paired: | ||
| 9 | case model_edit_type_t::link_remote: | ||
| 10 | case model_edit_type_t::unlink_remote: | ||
| 11 | 6 | c.shadeId = result.id; | |
| 12 | 6 | break; | |
| 13 | 2 | case model_edit_type_t::add_group: | |
| 14 | case model_edit_type_t::save_group: | ||
| 15 | 2 | c.groupId = result.id; | |
| 16 | 2 | break; | |
| 17 | // The shade's inGroup goes with it. | ||
| 18 | 2 | case model_edit_type_t::link_to_group: | |
| 19 | case model_edit_type_t::unlink_from_group: | ||
| 20 | 2 | c.groupId = result.id; | |
| 21 | 2 | c.shadeId = result.shadeId; | |
| 22 | 2 | break; | |
| 23 | 4 | case model_edit_type_t::add_room: | |
| 24 | case model_edit_type_t::save_room: | ||
| 25 | 4 | c.roomId = result.id; | |
| 26 | 4 | break; | |
| 27 | 1 | case model_edit_type_t::room_order: c.order = sort_list_t::rooms; break; | |
| 28 | 1 | case model_edit_type_t::shade_order: c.order = sort_list_t::shades; break; | |
| 29 | 1 | case model_edit_type_t::group_order: c.order = sort_list_t::groups; break; | |
| 30 | 2 | case model_edit_type_t::link_repeater: | |
| 31 | case model_edit_type_t::unlink_repeater: | ||
| 32 | 2 | c.repeaters = true; | |
| 33 | 2 | break; | |
| 34 | 1 | case model_edit_type_t::delete_room: c.removedRoomId = result.id; break; | |
| 35 | 1 | case model_edit_type_t::delete_shade: c.removedShadeId = result.id; break; | |
| 36 | 1 | case model_edit_type_t::delete_group: c.removedGroupId = result.id; break; | |
| 37 | } | ||
| 38 | 22 | return c; | |
| 39 | } | ||
| 40 | |||
| 41 | 4 | uint8_t firstFreeId(const uint8_t *usedIds, size_t count, uint8_t lastId) { | |
| 42 | 12 | for(uint16_t id = 1; id <= lastId; id++) { | |
| 43 | 11 | bool used = false; | |
| 44 | 34 | for(size_t i = 0; i < count && !used; i++) used = usedIds[i] == id; | |
| 45 | 11 | if(!used) return static_cast<uint8_t>(id); | |
| 46 | } | ||
| 47 | 1 | return 0; | |
| 48 | } | ||
| 49 | 2 | int8_t nextSortOrder(const int8_t *orders, size_t count) { | |
| 50 | 2 | int8_t order = -1; | |
| 51 | 6 | for(size_t i = 0; i < count; i++) | |
| 52 | 4 | if(orders[i] > order) order = orders[i]; | |
| 53 | 2 | return order + 1; | |
| 54 | } | ||
| 55 | 4 | uint32_t freeRemoteAddress(uint32_t candidate, const uint32_t *used, size_t count) { | |
| 56 | // Start over after every bump: the new address may be taken too. | ||
| 57 | 23 | for(size_t i = 0; i < count; i++) { | |
| 58 | 19 | if(used[i] == candidate) { | |
| 59 | 5 | candidate++; | |
| 60 | 5 | i = static_cast<size_t>(-1); | |
| 61 | } | ||
| 62 | } | ||
| 63 | 4 | return candidate; | |
| 64 | } | ||
| 65 | 2 | uint32_t offeredRemoteAddress(uint32_t startingAddress, uint8_t id, const uint32_t *used, size_t count) { | |
| 66 | 2 | return freeRemoteAddress(startingAddress + id, used, count); | |
| 67 | } | ||
| 68 | |||
| 69 | template<typename T> | ||
| 70 | 6 | static bool addTo(T *list, size_t size, T item) { | |
| 71 | 19 | for(size_t i = 0; i < size; i++) | |
| 72 | 15 | if(list[i] == item) return true; | |
| 73 | 9 | for(size_t i = 0; i < size; i++) { | |
| 74 | 8 | if(list[i] == 0) { | |
| 75 | 3 | list[i] = item; | |
| 76 | 3 | return true; | |
| 77 | } | ||
| 78 | } | ||
| 79 | 1 | return false; | |
| 80 | } | ||
| 81 | template<typename T> | ||
| 82 | 4 | static bool removeFrom(T *list, size_t size, T item) { | |
| 83 | 4 | bool removed = false; | |
| 84 | 4 | size_t j = 0; | |
| 85 | 22 | for(size_t i = 0; i < size; i++) { | |
| 86 | 18 | if(list[i] == 0) continue; | |
| 87 | 12 | if(list[i] == item) removed = true; | |
| 88 | 9 | else list[j++] = list[i]; | |
| 89 | } | ||
| 90 | 13 | while(j < size) list[j++] = 0; | |
| 91 | 4 | return removed; | |
| 92 | } | ||
| 93 | 1 | void packList(uint8_t *list, size_t size) { removeFrom<uint8_t>(list, size, 0); } | |
| 94 | 3 | bool addToList(uint8_t *list, size_t size, uint8_t item) { return addTo<uint8_t>(list, size, item); } | |
| 95 | 3 | bool addToList(uint32_t *list, size_t size, uint32_t item) { return addTo<uint32_t>(list, size, item); } | |
| 96 | 2 | bool removeFromList(uint8_t *list, size_t size, uint8_t item) { return removeFrom<uint8_t>(list, size, item); } | |
| 97 | 1 | bool removeFromList(uint32_t *list, size_t size, uint32_t item) { return removeFrom<uint32_t>(list, size, item); } | |
| 98 | |||
| 99 | 12 | int8_t gpioPinConflict(shade_types type, radio_proto proto, uint8_t upPin, uint8_t downPin, uint8_t myPin, | |
| 100 | const pin_users_t &radio, const pin_users_t ðernet, const pin_users_t &otherShades) { | ||
| 101 | 12 | if(proto != radio_proto::GP_Relay && proto != radio_proto::GP_Remote) return 0; | |
| 102 | // A dry contact or a single button gate driven by a remote only uses the down | ||
| 103 | // pin; a two way dry contact and a relay don't use My. | ||
| 104 | 11 | if(type == shade_types::drycontact || | |
| 105 | 9 | ((type == shade_types::garage1 || type == shade_types::lgate1 || type == shade_types::cgate1 || type == shade_types::rgate1) | |
| 106 | 2 | && proto == radio_proto::GP_Remote)) upPin = myPin = 255; | |
| 107 | 9 | else if(type == shade_types::drycontact2) myPin = 255; | |
| 108 | 11 | if(proto == radio_proto::GP_Relay) myPin = 255; | |
| 109 | 11 | const uint8_t pins[] = { upPin, downPin, myPin }; | |
| 110 | 29 | auto clash = [&pins](const pin_users_t &users) { | |
| 111 | 105 | for(uint8_t pin : pins) | |
| 112 | 81 | if(pin != 255 && users.usesPin(pin)) return true; | |
| 113 | 24 | return false; | |
| 114 | 11 | }; | |
| 115 | 11 | if(clash(radio)) return PIN_CONFLICT_RADIO; | |
| 116 | 10 | if(clash(ethernet)) return PIN_CONFLICT_ETHERNET; | |
| 117 | 8 | if(clash(otherShades)) return PIN_CONFLICT_SHADE; | |
| 118 | 6 | return 0; | |
| 119 | } | ||
| 120 |