dupontgu / retro-ipod-spotify-client

The software that powers the sPot: a 4th generation "Click Wheel" iPod with a full Spotify client.
Apache License 2.0
892 stars 90 forks source link

Q: High click.c CPU usage #44

Closed tomaculum closed 3 years ago

tomaculum commented 3 years ago

Hi everyone,

I noticed a very high CPU usage if I run just click even without the UI. Did anyone else notice this and did anyone find a better solution?

So far I have tried to rewrite the click.c code into a python class which could be used by the frontend directly, which was much worse performance wise.

Afterwards I have tried to adjust the sampling rate of the gpios but this resulted in only detecting up and down commands:

gpioCfgClock(8, 0, 0);

My latest effort was to make use of the pigpio daemon sudo pigpiod (add this command to /etc/xdg/openbox/autostart). And the following rewritten code but it does not seem to be any better.

click.c code ``` c // To compile on the pi (after installing pigpio): // gcc -Wall -pthread -o click click.c -lpigpiod_if2 -lrt #include #include #include #include #include #include #include #include #include #define CLOCK_PIN 23 #define DATA_PIN 17 #define HAPTIC_PIN 26 #define BIT_COUNT 32 #define PORT 9090 #define MAXLINE 1024 #define CENTER_BUTTON_BIT 7 #define LEFT_BUTTON_BIT 9 #define RIGHT_BUTTON_BIT 8 #define UP_BUTTON_BIT 11 #define DOWN_BUTTON_BIT 10 #define WHEEL_TOUCH_BIT 29 #define BUFFER_SIZE 3 #define BUTTON_INDEX 0 #define BUTTON_STATE_INDEX 1 #define WHEEL_POSITION_INDEX 2 // used to store the current packet uint32_t bits = 0; // used to store the previous full packet uint32_t lastBits = 0; uint8_t bitIndex = 0; uint8_t oneCount = 0; uint8_t recording = 0; // indicates whether the data pin is high or low uint8_t dataBit = 1; uint8_t lastPosition = 255; int pi = -1; int hapticWaveId = -1; char buttons[] = { CENTER_BUTTON_BIT, LEFT_BUTTON_BIT, RIGHT_BUTTON_BIT, UP_BUTTON_BIT, DOWN_BUTTON_BIT, WHEEL_TOUCH_BIT }; // all valid click wheel packets start with this const uint32_t PACKET_START = 0b01101; int sockfd; char buffer[BUFFER_SIZE]; char prev_buffer[BUFFER_SIZE]; struct sockaddr_in servaddr; // helper function to print packets as binary void printBinary(uint32_t value) { for(uint8_t i = 0; i < 32; i++) { if (value & 1) printf("1"); else printf("0"); value >>= 1; } printf("\n"); } // parse packet and broadcast data void sendPacket() { if ((bits & PACKET_START) != PACKET_START) { return; } for (size_t i = 0; i < BUFFER_SIZE; i++) { buffer[i] = -1; } for (size_t i = 0; i < sizeof(buttons); i++) { char buttonIndex = buttons[i]; if ((bits >> buttonIndex) & 1 && !((lastBits >> buttonIndex) & 1)) { buffer[BUTTON_INDEX] = buttonIndex; buffer[BUTTON_STATE_INDEX] = 1; printf("button pressed: %d\n", buttonIndex); } else if (!((bits >> buttonIndex) & 1) && (lastBits >> buttonIndex) & 1) { buffer[BUTTON_INDEX] = buttonIndex; buffer[BUTTON_STATE_INDEX] = 0; printf("button released: %d\n", buttonIndex); } } uint8_t wheelPosition = (bits >> 16) & 0xFF; // send haptics every other position. too sensitive otherwise if (wheelPosition != lastPosition && wheelPosition % 2 == 0) { if (hapticWaveId != -1) { wave_send_once(pi, hapticWaveId); } lastPosition = wheelPosition; } buffer[WHEEL_POSITION_INDEX] = wheelPosition; if (memcmp(prev_buffer, buffer, BUFFER_SIZE) == 0) { return; } printf("position %d\n", wheelPosition); lastBits = bits; sendto(sockfd, (const char *)buffer, BUFFER_SIZE, MSG_CONFIRM, (const struct sockaddr *) &servaddr, sizeof(servaddr)); memcpy(prev_buffer, buffer, BUFFER_SIZE); } // Function to set the kth bit of n int setBit(int n, int k) { return (n | (1 << (k - 1))); } // Function to clear the kth bit of n int clearBit(int n, int k) { return (n & (~(1 << (k - 1)))); } void onClockEdge(int pi, unsigned int gpio, unsigned int edge, unsigned int tick) { if (!edge) { // only care about rising edge return; } if (dataBit == 0) { recording = 1; oneCount = 0; } else { // 32 1's in a row means we're definitely not in the middle of a packet if (++oneCount >= BIT_COUNT) { recording = 0; bitIndex = 0; } } // in the middle of the packet if (recording == 1) { if (dataBit) { bits = setBit(bits, bitIndex); } else { bits = clearBit(bits, bitIndex); } // we've collected the whole packet if (++bitIndex == 32) { bitIndex = 0; sendPacket(); } } } void onDataEdge(int pi, unsigned int gpio, unsigned int edge, unsigned int tick) { dataBit = edge; } int main(int argc, char** argv){ // Creating socket file descriptor if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { perror("socket creation failed"); exit(EXIT_FAILURE); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(PORT); servaddr.sin_addr.s_addr = INADDR_ANY; pi = pigpio_start(0, 0); // haptic waveform - just a simple on-off pulse set_mode(pi, HAPTIC_PIN, PI_OUTPUT); gpioPulse_t pulse[2]; pulse[0].gpioOn = (1<

Is there a better or more efficient way to read the serial data from our clickwheel?

On the one hand I am a bit concerned by the heat generated by the CPU even while not even running anything else but click on the other hand I kind of want to avoid adding another component as such as an Arduino if it is not necessary.

nboumalham commented 3 years ago

Found a super easy solution

Add to the infinite while loop at the end of the code a sleep call :

while(1) {
     sleep(10000);
};

It's basically looping to stay running while listening to clickwheel actions....no need to kill the cpu with useless loop.

This is tried and tested for weeks now on my ipod.

dupontgu commented 3 years ago

Ah, good find @nboumalham - I totally meant to try that and see if it would impact the GPIO monitoring. Completely forgot. Feel free to open a PR with that fix!

tomaculum commented 3 years ago

Thank you very much!

nboumalham commented 3 years ago

Ah, good find @nboumalham - I totally meant to try that and see if it would impact the GPIO monitoring. Completely forgot. Feel free to open a PR with that fix!

Unfortunately I am not the most disciplined coder :/

I have added/changed SO MANY things and merged them into one main branch :

clickwheel:

A few other things.

I will see how I can created separate branches for each "feature" and propose a pull request if you approve them.

TheBasedDoge commented 2 years ago

Ah, good find @nboumalham - I totally meant to try that and see if it would impact the GPIO monitoring. Completely forgot. Feel free to open a PR with that fix!

Unfortunately I am not the most disciplined coder :/

I have added/changed SO MANY things and merged them into one main branch :

* A splash screen while loading stuff from Spotify

* The ability to control the volume in the now playing frame (including the GUI)

* Settings menu : view and connect to paired BT devices

* Settings menu: switch audio output if you have multiple audio outputs connected

* Settings menu: an about section with the version, capacity, used capacity, uptime etc (similar to iPOD ui, page scrolls with no items selected)

* Artists are now stored in alphabetical order

* Changed the GUI a bit (colors, forms, etc) and tried to match old monochrome LCD screens more (I will add a "theme switcher" so that people can maybe pick different themes. maybe even download them from some repo)

clickwheel:

* the ability to lock/unlock controls by pressing the menu button for 3 seconds (missing GUI showing lock)

* shutting down the ipod by pressing the play button for 5 seconds

A few other things.

I will see how I can created separate branches for each "feature" and propose a pull request if you approve them.

hi, im trying to get your fork to run but it's hanging on the apple splash screen. I installed the extra dependincies in requirements.txt..... what else would I need to install for it to run? How can i check what it's hanging on?

nboumalham commented 2 years ago

Sorry I'm on my phone right now. The best way to do it is probably by disabling the thread that loads up the spotify library while the apple logo is shown. just comment it out and return true (search for the word thread there is only one place it's used).

When you do this you will see the actual errors that the python is throwing.

If that doesn't help I'll look into it when I get home

TheBasedDoge commented 2 years ago

Sorry I'm on my phone right now. The best way to do it is probably by disabling the thread that loads up the spotify library while the apple logo is shown. just comment it out and return true (search for the word thread there is only one place it's used).

When you do this you will see the actual errors that the python is throwing.

If that doesn't help I'll look into it when I get home

I got past this, I looked at your comits and realized you replaced raspotify with spotifyd, so I set that up and now it loads to the menu and I can see my songs.

Problem now is selecting a song will not play it. if i start a song on my desktop app it shows that it's currently playing on the spotifypod though.

TheBasedDoge commented 2 years ago

Sorry I'm on my phone right now. The best way to do it is probably by disabling the thread that loads up the spotify library while the apple logo is shown. just comment it out and return true (search for the word thread there is only one place it's used).

When you do this you will see the actual errors that the python is throwing.

If that doesn't help I'll look into it when I get home

well i spoke too soon, i got it running on my test pi4 but then i went to do it on my actual ipod pi and its hanging again on the apple logo.

I must be doing something wrong. can you share your config for spotifyd? also i was not sure where to put the return true, i did find the section for thread

here is my pipod log root - ERROR - no ints root - ERROR - no ints root - ERROR - alsaaudio not compatible on this device root - ERROR - alsaaudio not compatible on this device root - ERROR - no ints root - ERROR - no ints

edit, ok i just installed alsaaduio and that error went away but still no go

TheBasedDoge commented 2 years ago

Sorry I'm on my phone right now. The best way to do it is probably by disabling the thread that loads up the spotify library while the apple logo is shown. just comment it out and return true (search for the word thread there is only one place it's used).

When you do this you will see the actual errors that the python is throwing.

If that doesn't help I'll look into it when I get home

I got everything working now, your version is much better! loads faster too.

2 things:

@nboumalham

doris1347 commented 1 year ago

Now, your version is much better! loads faster too.

2 things:

  • When i am on the main screen, and i press menu, the program closes and then i have no way to open it it again, so i have to reboot. is that normal?

  • Bluetooth is working to my galaxy buds but i have no volume control on the now playing screen. is it supposed to work? If i open spotify on my desktop and change the volume on the remote player from there it actually works.

@nboumalham

TheBasedDoge:

Were you able to get the volume control to work ???

TheBasedDoge commented 1 year ago

I never got it to work..... let me know if you make any progress on that

doris1347 commented 1 year ago

Nboumalham & Victor1234678,

Does controlling volume really work with your fork version, if yes would you please explain how to configure it to work?

Thanks!

doris1347 commented 1 year ago

TheBasedoge:

I never got it to work..... let me know if you make any progress on that

I did get everything working except volume with Raspotify didn't use Spotifyd.

I used the below version with Podcast:

https://github.com/viktor1234678/vPod

How did SpotifyD workout for you?

TheBasedDoge commented 1 year ago

Everything works for me besides volume, but I may try the version you posted.

doris1347 commented 1 year ago

Are you using SpotifyD? and do you find it better then Raspotify? Thank You!

TheBasedDoge commented 1 year ago

Yeah I am using spotifyD. It boots faster and seems to work smoother. Other than that same functionality.

doris1347 commented 1 year ago

Nboumalham,

Would you tell me what part of your code can be graphed into the DuPont default could to take advantage of the * shutting down the ipod by pressing the play button for 5 seconds?

Thanking you in advance.

henschelm commented 1 year ago

Hi, I also tried this and run into the same issue as TheBasedDoge. I configured spotifyd. Menue is up an running, but if I click onto a song it does not play. I only see the volume control. How did you come around this issue? Many thanks for your help! Marcus

doris1347 commented 1 year ago

Same here, couldn't get Bluetooth working hence could not play tracks. I since reverted to Mr. DuPont's default version using Raspotify instead of SpotifyD.

henschelm commented 1 year ago

Same here, couldn't get Bluetooth working hence could not play tracks. I since reverted to Mr. DuPont's default version using Raspotify instead of SpotifyD.

Dear Doris, many thanks for your Feedback. Did you tried the pulseaudio backend instead of alsa?

Cheers, Marcus

doris1347 commented 1 year ago

No I did not.