aboutsummaryrefslogtreecommitdiffstats
path: root/Projects/TemperatureDataLogger/Lib/SCSI.h
blob: 914ca7b61b57c2c5aa12b12a21c24b54ef739822 (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
/*
             LUFA Library
     Copyright (C) Dean Camera, 2010.
              
  dean [at] fourwalledcubicle [dot] com
      www.fourwalledcubicle.com
*/

/*
  Copyright 2010  Dean Camera (dean [at] fourwalledcubicle [dot] com)

  Permission to use, copy, modify, distribute, and sell this 
  software and its documentation for any purpose is hereby granted
  without fee, provided that the above copyright notice appear in 
  all copies and that both that the copyright notice and this
  permission notice and warranty disclaimer appear in supporting 
  documentation, and that the name of the author not be used in 
  advertising or publicity pertaining to distribution of the 
  software without specific, written prior permission.

  The author disclaim all warranties with regard to this
  software, including all implied warranties of merchantability
  and fitness.  In no event shall the author be liable for any
  special, indirect or consequential damages or any damages
  whatsoever resulting from loss of use, data or profits, whether
  in an action of contract, negligence or other tortious action,
  arising out of or in connection with the use or performance of
  this software.
*/

/** \file
 *
 *  Header file for SCSI.c.
 */
 
#ifndef _SCSI_H_
#define _SCSI_H_

	/* Includes: */
		#include <avr/io.h>
		#include <avr/pgmspace.h>

		#include <LUFA/Drivers/USB/USB.h>
		#include <LUFA/Drivers/USB/Class/MassStorage.h>

		#include "../TempDataLogger.h"
		#include "../Descriptors.h"
		#include "DataflashManager.h"
	
	/* Macros: */
		/** Macro to set the current SCSI sense data to the given key, additional sense code and additional sense qualifier. This
		 *  is for convenience, as it allows for all three sense values (returned upon request to the host to give information about
		 *  the last command failure) in a quick and easy manner.
		 *
		 *  \param[in] key    New SCSI sense key to set the sense code to
		 *  \param[in] acode  New SCSI additional sense key to set the additional sense code to
		 *  \param[in] aqual  New SCSI additional sense key qualifier to set the additional sense qualifier code to
		 */
		#define SCSI_SET_SENSE(key, acode, aqual)  MACROS{ SenseData.SenseKey = (key);                   \
		                                                   SenseData.AdditionalSenseCode = (acode);      \
		                                                   SenseData.AdditionalSenseQualifier = (aqual); }MACROE

		/** Macro for the SCSI_Command_ReadWrite_10() function, to indicate that data is to be read from the storage medium. */
		#define DATA_READ           true

		/** Macro for the SCSI_Command_ReadWrite_10() function, to indicate that data is to be written to the storage medium. */
		#define DATA_WRITE          false

		/** Value for the DeviceType entry in the SCSI_Inquiry_Response_t enum, indicating a Block Media device. */
		#define DEVICE_TYPE_BLOCK   0x00
		
		/** Value for the DeviceType entry in the SCSI_Inquiry_Response_t enum, indicating a CD-ROM device. */
		#define DEVICE_TYPE_CDROM   0x05
		
	/* Function Prototypes: */
		bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
		
		#if defined(INCLUDE_FROM_SCSI_C)
			static void SCSI_Command_Inquiry(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
			static void SCSI_Command_Request_Sense(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
			static void SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
			static void SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
			static void SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo, const bool IsDataRead);
		#endif
		
#endif
' href='#n462'>462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
/*
    ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
                 2011,2012 Giovanni Di Sirio.

    This file is part of ChibiOS/RT.

    ChibiOS/RT 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 3 of the License, or
    (at your option) any later version.

    ChibiOS/RT is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * @file    chevents.c
 * @brief   Events code.
 *
 * @addtogroup events
 * @details Event Flags, Event Sources and Event Listeners.
 *          <h2>Operation mode</h2>
 *          Each thread has a mask of pending event flags inside its @p Thread
 *          structure.
 *          Operations defined for event flags:
 *          - <b>Wait</b>, the invoking thread goes to sleep until a certain
 *            AND/OR combination of event flags becomes pending.
 *          - <b>Clear</b>, a mask of event flags is cleared from the pending
 *            events mask, the cleared event flags mask is returned (only the
 *            flags that were actually pending and then cleared).
 *          - <b>Signal</b>, an event mask is directly ORed to the mask of the
 *            signaled thread.
 *          - <b>Broadcast</b>, each thread registered on an Event Source is
 *            signaled with the event flags specified in its Event Listener.
 *          - <b>Dispatch</b>, an events mask is scanned and for each bit set
 *            to one an associated handler function is invoked. Bit masks are
 *            scanned from bit zero upward.
 *          .
 *          An Event Source is a special object that can be "broadcasted" by
 *          a thread or an interrupt service routine. Broadcasting an Event
 *          Source has the effect that all the threads registered on the
 *          Event Source will be signaled with an events mask.<br>
 *          An unlimited number of Event Sources can exists in a system and
 *          each thread can be listening on an unlimited number of
 *          them.
 * @pre     In order to use the Events APIs the @p CH_USE_EVENTS option must be
 *          enabled in @p chconf.h.
 * @post    Enabling events requires 1-4 (depending on the architecture)
 *          extra bytes in the @p Thread structure.
 * @{
 */

#include "ch.h"

#if CH_USE_EVENTS || defined(__DOXYGEN__)
/**
 * @brief   Registers an Event Listener on an Event Source.
 * @details Once a thread has registered as listener on an event source it
 *          will be notified of all events broadcasted there.
 * @note    Multiple Event Listeners can specify the same bits to be ORed to
 *          different threads.
 *
 * @param[in] esp       pointer to the  @p EventSource structure
 * @param[in] elp       pointer to the @p EventListener structure
 * @param[in] mask      the mask of event flags to be ORed to the thread when
 *                      the event source is broadcasted
 *
 * @api
 */
void chEvtRegisterMask(EventSource *esp, EventListener *elp, eventmask_t mask) {

  chDbgCheck((esp != NULL) && (elp != NULL), "chEvtRegisterMask");

  chSysLock();
  elp->el_next = esp->es_next;
  esp->es_next = elp;
  elp->el_listener = currp;
  elp->el_mask = mask;
  chSysUnlock();
}

/**
 * @brief   Unregisters an Event Listener from its Event Source.
 * @note    If the event listener is not registered on the specified event
 *          source then the function does nothing.
 * @note    For optimal performance it is better to perform the unregister
 *          operations in inverse order of the register operations (elements
 *          are found on top of the list).
 *
 * @param[in] esp       pointer to the  @p EventSource structure
 * @param[in] elp       pointer to the @p EventListener structure
 *
 * @api
 */
void chEvtUnregister(EventSource *esp, EventListener *elp) {
  EventListener *p;

  chDbgCheck((esp != NULL) && (elp != NULL), "chEvtUnregister");

  p = (EventListener *)esp;
  chSysLock();
  while (p->el_next != (EventListener *)esp) {
    if (p->el_next == elp) {
      p->el_next = elp->el_next;
      break;
    }
    p = p->el_next;
  }
  chSysUnlock();
}

/**
 * @brief   Clears the pending events specified in the mask.
 *
 * @param[in] mask      the events to be cleared
 * @return              The pending events that were cleared.
 *
 * @api
 */
eventmask_t chEvtClearFlags(eventmask_t mask) {
  eventmask_t m;

  chSysLock();

  m = currp->p_epending & mask;
  currp->p_epending &= ~mask;

  chSysUnlock();
  return m;
}

/**
 * @brief   Adds (OR) a set of event flags on the current thread, this is
 *          @b much faster than using @p chEvtBroadcast() or @p chEvtSignal().
 *
 * @param[in] mask      the event flags to be ORed
 * @return              The current pending events mask.
 *
 * @api
 */
eventmask_t chEvtAddFlags(eventmask_t mask) {

  chSysLock();

  mask = (currp->p_epending |= mask);

  chSysUnlock();
  return mask;
}

/**
 * @brief   Adds (OR) a set of event flags on the specified @p Thread.
 *
 * @param[in] tp        the thread to be signaled
 * @param[in] mask      the event flags set to be ORed
 *
 * @api
 */
void chEvtSignalFlags(Thread *tp, eventmask_t mask) {

  chDbgCheck(tp != NULL, "chEvtSignal");

  chSysLock();
  chEvtSignalFlagsI(tp, mask);
  chSchRescheduleS();
  chSysUnlock();
}

/**
 * @brief   Adds (OR) a set of event flags on the specified @p Thread.
 * @post    This function does not reschedule so a call to a rescheduling
 *          function must be performed before unlocking the kernel. Note that
 *          interrupt handlers always reschedule on exit so an explicit
 *          reschedule must not be performed in ISRs.
 *
 * @param[in] tp        the thread to be signaled
 * @param[in] mask      the event flags set to be ORed
 *
 * @iclass
 */
void chEvtSignalFlagsI(Thread *tp, eventmask_t mask) {

  chDbgCheckClassI();
  chDbgCheck(tp != NULL, "chEvtSignalI");

  tp->p_epending |= mask;
  /* Test on the AND/OR conditions wait states.*/
  if (((tp->p_state == THD_STATE_WTOREVT) &&
       ((tp->p_epending & tp->p_u.ewmask) != 0)) ||
      ((tp->p_state == THD_STATE_WTANDEVT) &&
       ((tp->p_epending & tp->p_u.ewmask) == tp->p_u.ewmask)))
    chSchReadyI(tp)->p_u.rdymsg = RDY_OK;
}

/**
 * @brief   Signals all the Event Listeners registered on the specified Event
 *          Source.
 * @details This function variants ORs the specified event flags to all the
 *          threads registered on the @p EventSource in addition to the event
 *          flags specified by the threads themselves in the
 *          @p EventListener objects.
 *
 * @param[in] esp       pointer to the @p EventSource structure
 * @param[in] mask      the event flags set to be ORed
 *
 * @api
 */
void chEvtBroadcastFlags(EventSource *esp, eventmask_t mask) {

  chSysLock();
  chEvtBroadcastFlagsI(esp, mask);
  chSchRescheduleS();
  chSysUnlock();
}

/**
 * @brief   Signals all the Event Listeners registered on the specified Event
 *          Source.
 * @details This function variants ORs the specified event flags to all the
 *          threads registered on the @p EventSource in addition to the event
 *          flags specified by the threads themselves in the
 *          @p EventListener objects.
 * @post    This function does not reschedule so a call to a rescheduling
 *          function must be performed before unlocking the kernel. Note that
 *          interrupt handlers always reschedule on exit so an explicit
 *          reschedule must not be performed in ISRs.
 *
 * @param[in] esp       pointer to the @p EventSource structure
 * @param[in] mask      the event flags set to be ORed
 *
 * @iclass
 */
void chEvtBroadcastFlagsI(EventSource *esp, eventmask_t mask) {
  EventListener *elp;

  chDbgCheckClassI();
  chDbgCheck(esp != NULL, "chEvtBroadcastMaskI");

  elp = esp->es_next;
  while (elp != (EventListener *)esp) {
    chEvtSignalFlagsI(elp->el_listener, elp->el_mask | mask);
    elp = elp->el_next;
  }
}

/**
 * @brief   Invokes the event handlers associated to an event flags mask.
 *
 * @param[in] mask      mask of the event flags to be dispatched
 * @param[in] handlers  an array of @p evhandler_t. The array must have size
 *                      equal to the number of bits in eventmask_t.
 *
 * @api
 */
void chEvtDispatch(const evhandler_t *handlers, eventmask_t mask) {
  eventid_t eid;

  chDbgCheck(handlers != NULL, "chEvtDispatch");

  eid = 0;
  while (mask) {
    if (mask & EVENT_MASK(eid)) {
      chDbgAssert(handlers[eid] != NULL,
                  "chEvtDispatch(), #1",
                  "null handler");
      mask &= ~EVENT_MASK(eid);
      handlers[eid](eid);
    }
    eid++;
  }
}

#if CH_OPTIMIZE_SPEED || !CH_USE_EVENTS_TIMEOUT || defined(__DOXYGEN__)
/**
 * @brief   Waits for exactly one of the specified events.
 * @details The function waits for one event among those specified in
 *          @p mask to become pending then the event is cleared and returned.
 * @note    One and only one event is served in the function, the one with the
 *          lowest event id. The function is meant to be invoked into a loop in
 *          order to serve all the pending events.<br>
 *          This means that Event Listeners with a lower event identifier have
 *          an higher priority.
 *
 * @param[in] mask      mask of the event flags that the function should wait
 *                      for, @p ALL_EVENTS enables all the events
 * @return              The mask of the lowest id served and cleared event.
 *
 * @api
 */
eventmask_t chEvtWaitOne(eventmask_t mask) {
  Thread *ctp = currp;
  eventmask_t m;

  chSysLock();

  if ((m = (ctp->p_epending & mask)) == 0) {
    ctp->p_u.ewmask = mask;
    chSchGoSleepS(THD_STATE_WTOREVT);
    m = ctp->p_epending & mask;
  }
  m &= -m;
  ctp->p_epending &= ~m;

  chSysUnlock();
  return m;
}

/**
 * @brief   Waits for any of the specified events.
 * @details The function waits for any event among those specified in
 *          @p mask to become pending then the events are cleared and returned.
 *
 * @param[in] mask      mask of the event flags that the function should wait
 *                      for, @p ALL_EVENTS enables all the events
 * @return              The mask of the served and cleared events.
 *
 * @api
 */
eventmask_t chEvtWaitAny(eventmask_t mask) {
  Thread *ctp = currp;
  eventmask_t m;

  chSysLock();

  if ((m = (ctp->p_epending & mask)) == 0) {
    ctp->p_u.ewmask = mask;
    chSchGoSleepS(THD_STATE_WTOREVT);
    m = ctp->p_epending & mask;
  }
  ctp->p_epending &= ~m;

  chSysUnlock();
  return m;
}

/**
 * @brief   Waits for all the specified events.
 * @details The function waits for all the events specified in @p mask to
 *          become pending then the events are cleared and returned.
 *
 * @param[in] mask      mask of the event flags that the function should wait
 *                      for, @p ALL_EVENTS requires all the events
 * @return              The mask of the served and cleared events.
 *
 * @api
 */
eventmask_t chEvtWaitAll(eventmask_t mask) {
  Thread *ctp = currp;

  chSysLock();

  if ((ctp->p_epending & mask) != mask) {
    ctp->p_u.ewmask = mask;
    chSchGoSleepS(THD_STATE_WTANDEVT);
  }
  ctp->p_epending &= ~mask;

  chSysUnlock();
  return mask;
}
#endif /* CH_OPTIMIZE_SPEED || !CH_USE_EVENTS_TIMEOUT */

#if CH_USE_EVENTS_TIMEOUT || defined(__DOXYGEN__)
/**
 * @brief   Waits for exactly one of the specified events.
 * @details The function waits for one event among those specified in
 *          @p mask to become pending then the event is cleared and returned.
 * @note    One and only one event is served in the function, the one with the
 *          lowest event id. The function is meant to be invoked into a loop in
 *          order to serve all the pending events.<br>
 *          This means that Event Listeners with a lower event identifier have
 *          an higher priority.
 *
 * @param[in] mask      mask of the event flags that the function should wait
 *                      for, @p ALL_EVENTS enables all the events
 * @param[in] time      the number of ticks before the operation timeouts,
 *                      the following special values are allowed:
 *                      - @a TIME_IMMEDIATE immediate timeout.
 *                      - @a TIME_INFINITE no timeout.
 *                      .
 * @return              The mask of the lowest id served and cleared event.
 * @retval 0            if the operation has timed out.
 *
 * @api
 */
eventmask_t chEvtWaitOneTimeout(eventmask_t mask, systime_t time) {
  Thread *ctp = currp;
  eventmask_t m;

  chSysLock();

  if ((m = (ctp->p_epending & mask)) == 0) {
    if (TIME_IMMEDIATE == time) {
      chSysUnlock();
      return (eventmask_t)0;
    }
    ctp->p_u.ewmask = mask;
    if (chSchGoSleepTimeoutS(THD_STATE_WTOREVT, time) < RDY_OK) {
      chSysUnlock();
      return (eventmask_t)0;
    }
    m = ctp->p_epending & mask;
  }
  m &= -m;
  ctp->p_epending &= ~m;

  chSysUnlock();
  return m;
}

/**
 * @brief   Waits for any of the specified events.
 * @details The function waits for any event among those specified in
 *          @p mask to become pending then the events are cleared and
 *          returned.
 *
 * @param[in] mask      mask of the event flags that the function should wait
 *                      for, @p ALL_EVENTS enables all the events
 * @param[in] time      the number of ticks before the operation timeouts,
 *                      the following special values are allowed:
 *                      - @a TIME_IMMEDIATE immediate timeout.
 *                      - @a TIME_INFINITE no timeout.
 *                      .
 * @return              The mask of the served and cleared events.
 * @retval 0            if the operation has timed out.
 *
 * @api
 */
eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, systime_t time) {
  Thread *ctp = currp;
  eventmask_t m;

  chSysLock();

  if ((m = (ctp->p_epending & mask)) == 0) {
    if (TIME_IMMEDIATE == time) {
      chSysUnlock();
      return (eventmask_t)0;
    }
    ctp->p_u.ewmask = mask;
    if (chSchGoSleepTimeoutS(THD_STATE_WTOREVT, time) < RDY_OK) {
      chSysUnlock();
      return (eventmask_t)0;
    }
    m = ctp->p_epending & mask;
  }
  ctp->p_epending &= ~m;

  chSysUnlock();
  return m;
}

/**
 * @brief   Waits for all the specified events.
 * @details The function waits for all the events specified in @p mask to
 *          become pending then the events are cleared and returned.
 *
 * @param[in] mask      mask of the event flags that the function should wait
 *                      for, @p ALL_EVENTS requires all the events
 * @param[in] time      the number of ticks before the operation timeouts,
 *                      the following special values are allowed:
 *                      - @a TIME_IMMEDIATE immediate timeout.
 *                      - @a TIME_INFINITE no timeout.
 *                      .
 * @return              The mask of the served and cleared events.
 * @retval 0            if the operation has timed out.
 *
 * @api
 */
eventmask_t chEvtWaitAllTimeout(eventmask_t mask, systime_t time) {
  Thread *ctp = currp;

  chSysLock();

  if ((ctp->p_epending & mask) != mask) {
    if (TIME_IMMEDIATE == time) {
      chSysUnlock();
      return (eventmask_t)0;
    }
    ctp->p_u.ewmask = mask;
    if (chSchGoSleepTimeoutS(THD_STATE_WTANDEVT, time) < RDY_OK) {
      chSysUnlock();
      return (eventmask_t)0;
    }
  }
  ctp->p_epending &= ~mask;

  chSysUnlock();
  return mask;
}
#endif /* CH_USE_EVENTS_TIMEOUT */

#endif /* CH_USE_EVENTS */

/** @} */