(2025-03-31, 01:19 AM)emily Wrote: Quote:Is this considered the default orientation for Tangarine's buttons?
To the extent I get to define a default, sure? It means that in the default button layout, the triangle is a back arrow and the X is the stop/clear queue button, which makes sense to me. But it fits in any of the 8 possible orientations.
Which functions are the square and circle buttons set to?
(2025-04-09, 03:55 AM)emily Wrote: Not currently, but there could be!
I think what I'm going to do is do a quick DFM pass, send off a small batch of the boards to be professionally assembled to whatever extent seems like a good trade of money for time (ugh, I'd pay someone solely to reliably solder the FFC connector on for me), and throw them on... Tindie? Do people still use Tindie? Is there a thing people use instead of Tindie? Is there a thing like CrowdSupply but just the warehouse part and not the crowdfunding part?
I don't expect too many more to ever be made, and I'm going to be moving later this year so I don't want to commit to too many more projects, but there are a couple more people who want one and can't build one themselves, and this seems like a reasonable thing to do. Thanks for the reply. Yes, people do still use tindie
(2025-04-10, 01:16 PM)taivlam Wrote: Which functions are the square and circle buttons set to?
In the default config, long-pressing bottom-left clears the queue, and pressing bottom-right goes to the now-playing screen.
Got a DM about this today, so update:
I have all the parts on hand to assemble a second batch of these. Average of what people sent me for the pay-what-you-want batch was around $50 shipped, so that's probably what it'd be for a fixed-cost batch?
However, I'm moving across the country sometime in the next few months, and that and related things have been taking up all my free time and mental energy. So I don't know at the moment whether I'll get back to this before then. I might, but I might not. I'm not going to take anyone's money before I have finished things to sell them, though; there isn't anywhere near enough money involved in this particular project to justify crowdfunding or paid preorders.
(This is also why the Lua input PR has been languishing recently. There's one very tricky memory corruption bug remaining, and I have not had the chance to sit down and figure out wtf is happening. Sorry about that.)
2025-05-02, 02:55 AM
(Edited 2025-05-02, 04:14 AM by taivlam.)
(2025-05-01, 04:36 PM)emily Wrote: (This is also why the Lua input PR has been languishing recently. There's one very tricky memory corruption bug remaining, and I have not had the chance to sit down and figure out wtf is happening. Sorry about that.)
I got a little anxious with my Tangarine lying around and I wanted to try to at the very least determine if the faceplate device works. (@redshift got Tangarine to work, so I thought maybe I could get custom firmware to work.) I felt like a fish out of water trying to build the Tangarine firmware from source.
- Before I started, I installed `esp-idf` from the AUR and also followed its own corresponding directions for installation.
- First, I used this Git branch: https://codeberg.org/bloop/tangara-fw/sr...ut-drivers
- Next, I used this command: `git clone https://codeberg.org/bloop/tangara-fw.git && cd tangara-fw && git switch emily/lua-input-drivers`
- I followed the build directions from upstream: https://codeberg.org/cool-tech-zone/tang...UILDING.md
Resolved, see below.
However, I have encountered an issue: when I've tried to flash the Tangarine firmware, Tangara now enters a boot loop situation. At first, it will turn on seemingly normal. However, only the volume buttons and lock slider work. None of the Tangarine buttons work when pressed. About 28 seconds after booting up, Tangara will restart. Is this the memory corruption bug that you've mentioned? (I should've realized that there was a bit of foreshadowing, as I noticed Tangara restart by itself after successful firmware flashing via the CLI.) Or have I done something wrong with building from source?
One observation: the SD card menu icon isn't immediately displayed if I don't provide any user interaction. However, the menu can be brought up if you (rather quickly) manually eject and reinsert Tangara's SD card. (The effect doesn't last long, however, as Tangara will boot loop).
The one good thing I learned is that I can use the Tangara Companion GUI to "flash" the upstream Tangara firmware if any custom firmware isn't working out as expected. When I flash the normal firmware (even with the Tangarine face plate), Tangara doesn't experience the same boot looping situation.
(I'm a bit nervous that I might've not reassembled my Tangara with Tangarine gently earlier today. I currently don't have the vanilla faceplate with me, but it should be back in my possession tomorrow. Regardless, I believe the signs right now don't indicate that there was hardware damage with the flex cable.)
2025-05-02, 04:17 AM
(Edited 2025-05-02, 04:18 AM by taivlam.)
The last step to allow Tangarine to work properly is to save this `input.lua` file into the root directory of your Tangara's SD card: https://codeberg.org/bloop/tangarine/src.../input.lua
Otherwise, Tangara will boot loop without `input.lua`. (I hope this tip helps anyone who uses Tangarine in the future.)
2025-05-02, 04:31 AM
(Edited 2025-05-02, 04:38 AM by emily.)
Ah, yes, without an input.lua it won't know what to do with the buttons. It's expected that the buttons don't work without it.
But that shouldn't cause crashing; that's very much not expected behavior. This does perhaps explain why jacqueline seemed to get much more frequent crashes than I did; I either had an SD card with input.lua inserted, or had the SD card out entirely. I will look into that when I get back around to this.
Quote:The one good thing I learned is that I can use the Tangara Companion GUI to "flash" the upstream Tangara firmware if any custom firmware isn't working out as expected.
This is the result of some good design choices on CTZ's part; it's *very* hard to brick the Tangara by messing with the main ESP firmware. (SAMD firmware is probably harder to recover, but that's okay, because nobody ever needs to mess with the SAMD firmware anyway.)
2025-05-02, 04:57 AM
(Edited 2025-05-17, 12:29 PM by taivlam.)
So, is there a way to tell the difference between if the bottom right/southeast button on my Tangarine is physically broken vs. if the firmware isn't working as intended? Right now, I can't use the SE button to go to the "Now Playing" menu.
I've only used Tangarine for a bit, but I feel confident that all other buttons work. So far, I like how Tangara lets me go through playlist entries much quicker than the default touchwheel faceplate.
Latest commit on the lua-input branch should fix the crashing that happens when input.lua is missing.
Quote:So, is there a way to tell the difference between if the bottom right/southeast button on my Tangarine is physically broken vs. if the firmware isn't working as intended? Right now, I can't use the SE button to go to the "Now Playing" menu.
There's no reason that specific button should behave differently than the others, assuming you have a mapping for it in input.lua. You could try replacing your input.lua with the script I use for hardware testing, and watching the debug console ( idf.py monitor from your build environment); it'll print all the button states whenever they change.
If it's a hardware problem, you could try just... pushing the button really hard to nudge it back into working. I had to do that occasionally on my original prototype.
2025-05-12, 12:54 AM
(Edited 2025-05-12, 10:31 PM by emily.)
Update: I have Done The Thing. 5 assembled and tested, listing awaiting approval from Tindie here: https://www.tindie.com/products/_emily/tangarine/
taivlam, if yours is still misbehaving I'd be happy to send you one of the boards from this batch to replace it.
2025-05-17, 12:35 PM
(Edited 2025-05-17, 12:48 PM by taivlam.)
(2025-05-03, 03:57 AM)emily Wrote: If it's a hardware problem, you could try just... pushing the button really hard to nudge it back into working. I had to do that occasionally on my original prototype.
I've tried pushing that SE button as strongly as I could (though I had to stop in order to not break the rest of my Tangara) to no avail. At this rate, I've accepted that the SE button is not working, whatever the cause is.
Hypothetically, I could attempt resoldering, but I have no experience with micro soldering and I also don't have the tools right now to microsolder.
I haven't tried debugging via "idf.py" yet.
I've had the capacitive touchwheel bug out on me on multiple occasions lately where I couldn't scroll continuously in one direction, it would keep scrolling back and forth. This happened when my finger was wet, but has also happened when my hand was dry. I think buttons will be more reliable.
2025-05-24, 04:19 AM
(Edited 2025-05-25, 01:45 PM by emily.)
For whichever one of you has Tindie order 534914 and is wondering why you've had a tracking number for four days and I haven't actually sent you anything:
I ordered boxes from USPS expecting them to arrive the next day like they usually do, but they... did not. Supposedly they'll show up tomorrow. If not, tomorrow afternoon I'll go to the post office awkwardly carrying a bunch of loose parts and bubble wrap, and pack it up there. Sorry for the delay!
edit: post office was closed and they now estimate another week to deliver some empty boxes, so I gave up and cancelled the shipment and created another one with a non-flat-rate box. Check your email for the tracking number.
(2025-03-23, 04:32 AM)redshift Wrote: I love that I can tweak the input.lua to do different things, and even scroll faster through my large library.
Hi redshift, did you ever test that the bottom right button works in your edits to the input.file, for pulling up the "Now Playing" menu when music is playing?
Emily and I are both finding independently that this functionality isn't working in the current input.lua file. I'm discovering this only now because I had received a replacement faceplate board, because initially I thought maybe this button didn't work for my Tangarine. However, after receiving a replacement board, I refused to believe that both boards have a PCB connection issue exactly at the bottom right button.
(2025-05-29, 08:09 AM)taivlam Wrote: Hi redshift, did you ever test that the bottom right button works in your edits to the input.file, for pulling up the "Now Playing" menu when music is playing?
Emily and I are both finding independently that this functionality isn't working in the current input.lua file. I'm discovering this only now because I had received a replacement faceplate board, because initially I thought maybe this button didn't work for my Tangarine. However, after receiving a replacement board, I refused to believe that both boards have a PCB connection issue exactly at the bottom right button.
It does work for me, but I haven't updated beyond this commit, so if you're both having consistent issues, I would guess it's related to something from the range of commits between 6ce293184e and 08a6aa2b33 (based on this list as of the time of this posting). I believe the new commits were intended to address concerns raised in the PR, but I never had any issues with commit 95af1ab458 so I hadn't updated.
I'm really hoping the issues can be worked out so this can be upstreamed! I don't want to maintain a fork forever, but the buttons are so much better than the wheel for me.
I'll update to the latest commit and report on my results. It'll be useful to know whether I have the same problem with that button.
I've updated to the latest commit (08a6aa2b33) from the PR and I'm happy to report that everything still works, even the bottom-right button. This is my definition for that button:
Code: [2] = {
click = function()
-- Go to now-playing screen
require("playing"):push_if_not_shown()
end,
},
I'm happy to no longer need the eval_on_ui_thread call!
I have no idea why it wouldn't work for you, though. If you're using similar code, and you've already replaced the faceplate, and Emily has the same issue... it seems that either I'm doing something "wrong" (that in fact makes it work) or you're both very unlucky. I'm probably doing something different, given those odds. All I'm doing is a build and flash based on that latest commit, though. I'll put my full input.lua here in case there's some other difference:
Code: local i2c = require('i2c')
local gpio = require('gpio')
local input_device = require('input_device')
local queue = require('queue')
local playback = require('playback')
local time = require('time')
local backstack = require("backstack")
--[[
Up to 16 buttons are supported with this driver.
If you assign actions to buttons you don't have, they will appear to always be pressed, so don't do that.
Tangarine button layout:
6 7 0
5 8 1
4 3 2
Actions that can be assigned per button:
[0] = {
click = function()
-- button was pressed and released once
end,
doubleclick = function()
-- button was pressed and released twice
end
press = function()
-- button was just pressed, not released yet
end,
longpress = function()
-- button was held
end,
repeatpress = function()
-- button is still being held after longpress
end,
},
You can perform arbitrary actions in these functions, or return data to be wrapped into an lvgl input event.
If returning data, it should be a table containing zero or more of the keys:
{
encoder_diff = (integer),
encoder_button_pressed = (boolean),
}
]]
local button_map = {
-- Top-right button
[0] = {
press = function()
if (not playback.track:get()) then
-- Restart the last played track
queue.position:set(queue.position:get())
end
playback.playing:set(not playback.playing:get())
end,
},
-- Right button
[1] = {
click = function()
queue:next()
end,
},
-- Bottom-right button
[2] = {
click = function()
-- Go to now-playing screen
require("playing"):push_if_not_shown()
end,
},
-- Bottom button
[3] = {
-- "doing literally anything to these buttons results in movement" feels more responsive to me
press = function()
return { encoder_diff = 1 }
end,
-- Hold down for fast scroll
repeatpress = function()
return { encoder_diff = 10 }
end,
doubleclick = function()
return { encoder_diff = 1 }
end,
},
-- Bottom-left button
[4] = {
longpress = function()
queue.clear()
end,
},
-- Left button
[5] = {
click = function()
if playback.position:get() > 3 then
playback.position:set(0)
else
queue.previous()
end
end,
},
-- Top-left button
[6] = {
longpress = function()
backstack.reset(require("main_menu"):new())
end,
click = function()
backstack.pop()
end
},
-- Top button
[7] = {
press = function()
return { encoder_diff = -1 }
end,
repeatpress = function()
return { encoder_diff = -10 }
end,
doubleclick = function()
return { encoder_diff = -1 }
end,
},
-- Center button
[8] = {
click = function()
return { encoder_button_pressed = true }
end,
},
}
local triggers = {}
local function buttons_setup()
for reg, value in pairs({
[6] = 0xFF, -- direction low: all pins inputs
[7] = 0xFF, -- direction high
[4] = 0xFF, -- invert low: all pins active low
[5] = 0xFF, -- invert high
}) do
i2c.execute(
i2c.start(),
i2c.write_addr(0x27, 'write'),
i2c.write_ack(reg),
i2c.write_ack(value),
i2c.stop()
)
end
for i = 0, 15 do
triggers[i] = input_device.make_trigger()
end
end
local button_states = {}
local locked = false
local function buttons_read()
if gpio.get_faceplate_interrupt_level() == 0 then
local input_low, input_high = i2c.execute(
i2c.start(),
i2c.write_addr(0x27, 'write'),
i2c.write_ack(0), -- input low
i2c.start(),
i2c.write_addr(0x27, 'read'),
i2c.read(),
i2c.read('nack'),
i2c.stop()
)
for i = 0, 7 do
button_states[i] = (input_low & (1 << i)) ~= 0
button_states[i + 8] = (input_high & (1 << i)) ~= 0
end
end
local merged_event = {
encoder_diff = 0,
encoder_button_pressed = false,
}
for i = 0, 15 do
local state = triggers[i]:update(button_states[i])
if not locked and button_map[i] and button_map[i][state] then
local ev = button_map[i][state]()
if type(ev) == 'table' then
if type(ev.encoder_diff) == 'number' then
merged_event.encoder_diff = merged_event.encoder_diff + ev.encoder_diff
end
if type(ev.encoder_button_pressed) == 'boolean' then
merged_event.encoder_button_pressed = (merged_event.encoder_button_pressed or ev.encoder_button_pressed)
end
end
end
end
return merged_event
end
buttons_setup()
input_device.register_read_func(buttons_read)
input_device.register_lock_func(function()
locked = true
end)
input_device.register_unlock_func(function()
locked = false
end)
Quote:I'm happy to no longer need the eval_on_ui_thread call!
... y'all, I might be a dumbass
I can't test at the moment, but taivlam, can you try the latest input.lua when you have a chance?
|