summaryrefslogtreecommitdiffstats
path: root/uisimulator/common/sim_tasks.c
blob: f154dacce618d88afa190a238346a032ffd0d878 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (C) 2009 by Jens Arnold
 * Copyright (C) 2011 by Thomas Martitz
 *
 * Rockbox simulator specific tasks
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/

#include "config.h"
#include "kernel.h"
#include "screendump.h"
#include "thread.h"
#include "debug.h"
#include "usb.h"

static void sim_thread(void);
static long sim_thread_stack[DEFAULT_STACK_SIZE/sizeof(long)];
            /* stack isn't actually used in the sim */
static const char sim_thread_name[] = "sim";
static struct event_queue sim_queue;

/* possible events for the sim thread */
enum {
    SIM_SCREENDUMP,
    SIM_USB_INSERTED,
    SIM_USB_EXTRACTED,
};

void sim_thread(void)
{
    struct queue_event ev;
    long last_broadcast_tick = current_tick;
    int num_acks_to_expect;
    
    while (1)
    {
        queue_wait(&sim_queue, &ev);
        switch(ev.id)
        {
            case SIM_SCREENDUMP:
                screen_dump();
#ifdef HAVE_REMOTE_LCD
                remote_screen_dump();
#endif
                break;
            case SIM_USB_INSERTED:
            /* from firmware/usb.c: */
                /* Tell all threads that they have to back off the storage.
                   We subtract one for our own thread. Expect an ACK for every
                   listener for each broadcast they received. If it has been too
                   long, the user might have entered a screen that didn't ACK
                   when inserting the cable, such as a debugging screen. In that
                   case, reset the count or else USB would be locked out until
                   rebooting because it most likely won't ever come. Simply
                   resetting to the most recent broadcast count is racy. */
                if(TIME_AFTER(current_tick, last_broadcast_tick + HZ*5))
                {
                    num_acks_to_expect = 0;
                    last_broadcast_tick = current_tick;
                }

                num_acks_to_expect += queue_broadcast(SYS_USB_CONNECTED, 0) - 1;
                DEBUGF("USB inserted. Waiting for %d acks...\n",
                       num_acks_to_expect);
                break;
            case SYS_USB_CONNECTED_ACK:
                if(num_acks_to_expect > 0 && --num_acks_to_expect == 0)
                {
                    DEBUGF("All threads have acknowledged the connect.\n");
                }
                else
                {
                    DEBUGF("usb: got ack, %d to go...\n",
                           num_acks_to_expect);
                }
                break;
            case SIM_USB_EXTRACTED:
                /* in usb.c, this is only done for exclusive storage
                 * do it here anyway but don't depend on the acks */
                queue_broadcast(SYS_USB_DISCONNECTED, 0);
                break;
            default:
                DEBUGF("sim_tasks: unhandled event: %ld\n", ev.id);
                break;
        }
    }
}

void sim_tasks_init(void)
{
    queue_init(&sim_queue, false);
    
    create_thread(sim_thread, sim_thread_stack, sizeof(sim_thread_stack), 0,
                  sim_thread_name IF_PRIO(,PRIORITY_BACKGROUND) IF_COP(,CPU));
}

void sim_trigger_screendump(void)
{
    queue_post(&sim_queue, SIM_SCREENDUMP, 0);
}

static bool is_usb_inserted;
void sim_trigger_usb(bool inserted)
{
    if (inserted)
        queue_post(&sim_queue, SIM_USB_INSERTED, 0);
    else
        queue_post(&sim_queue, SIM_USB_EXTRACTED, 0);
    is_usb_inserted = inserted;
}

int usb_detect(void)
{
    return is_usb_inserted ? USB_INSERTED : USB_EXTRACTED;
}

void usb_init(void)
{
}

void usb_start_monitoring(void)
{
}

void usb_acknowledge(long id)
{
    queue_post(&sim_queue, id, 0);
}

void usb_wait_for_disconnect(struct event_queue *q)
{
#ifdef USB_FULL_INIT
    struct queue_event ev;

    /* Don't return until we get SYS_USB_DISCONNECTED */
    while(1)
    {
        queue_wait(q, &ev);
        if(ev.id == SYS_USB_DISCONNECTED)
            return;
    }
#endif /* USB_FULL_INIT */
    (void)q;
}